RCTF2019 pwn chat writeup
TOC
堆溢出类型,难点在于程序及其复杂的结构体,赛时靶机环境是glibc-2.27,下面所讲的symbols在IDA分析文件中均有对应。
源程序和相关文件下载:chat.zip 。
安全防护
ex@Ex:~/test$ checksec chat |
简介
程序里面是一堆及其复杂的结构,我们不可能把每一个函数都进行仔细分析,只需要在关键点下断点就行了,比如sync
函数,modify
功能,在这些地址下断点,并观察其执行前的状态和执行后的状态,然后进行对比,这样能更快理解程序。
溢出点
sync
mmap_addr->message->message
原本应该是字符串的,但在sync函数中却被当成偏移来使用,所以造成了该漏洞,这个比较容易发现,因为这个漏洞会直接造成程序crash。
message_list = (struc_message *)malloc(0x30uLL); |
now和user_list
now是一开始就初始化好的,在程序中一直指向260
chunk,但是在sync
函数中,会进行一次更新操作,而且tcache是FIFO模式
,也就意味着我们可以利用别的结构来控制now的260
chunk。最好的理解方式就是画图。
调试结果如下所示,所以now的每一次被写入的结果都是可预测的。
Breakpoint sync |
思路
- 泄露libc
- free假的chunk
- double free
- 劫持hook
泄露libc
因为mmap申请的内存每次和libc
的偏移是固定的,可以利用sync
的溢出点泄露libc地址。
sh.recvuntil("please enter your name: ") |
fake_chunk
sh.sendline('') |
这里用到了上面我们在name
中构造的fake_chunk
,原理是注入payload之后,在更新时,由于payload的chunk是0x30
的size,刚好可以符合struct name
的长度,所以可以通过同步,来控制260
chunk的内容,也就是now的值。这样就可以直接free掉我们伪造的chunk。
调试结果如下:
Breakpoint sync |
可以看到,执行完sync
函数后,user_list->name
用的是260
chunk,也就是意味这now可以被我们所控制,所以now->user_name
已经是我们伪造的chunk的地址。
double free
这里同理,进行double free
,那么就可以在tcache中写入__free_hook
。
# pause() |
结果如下:
pwndbg> bin |
劫持hook
消耗掉前面的0x603190
,之后便可以拿出__free_hook
,将__free_hook
改为system
从而拿到shell。
sh.sendline('modify ' + p64(libc_addr + libc.symbols['__free_hook'])) |
完整代码
#!/usr/bin/python2 |
运行实例
ex@Ex:~/test$ ./exp.py |
总结
对于这种复杂的程序想把其吃透是很难的,所以最好的方式就是仔细分析其关键路径,进而在当中挖掘漏洞。