利用IO进行泄露的利用手法
前言
是neise1最近做到iscc里的一道堆题,是经典的笔记管理题,有UAF,不过没有show,所以一时之间不知道怎么泄露libc地址,后面查到了这种泄露方式,就学习了一下,并写了这篇博客。
利用手法
在这里贴一下_IO_FILE结构体的大致结构
1 | struct _IO_FILE { |
首先,我们需要能去改写stdout指针处存储的_IO_2_1_stdout_该IO_FILE结构体,然后修改其_flags为0xfbad1800(根据puts函数的源码所得),将后面三个read指针置空,将_IO_write_base处的第一个字节改为0x58,后面的_IO_write_ptr和_IO_write_end保持不变。之后当程序遇到puts函数时就会打印_IO_write_base到_IO_write_ptr之间的内容,按照上面步骤改动的话,我们泄露出的第一个libc地址是_IO_file_jumps,也就是一个libc地址。
这里贴几个常用的payload。
1 | payload = p64(0xfbad1800)+p64(0)*3+b"\x58" |
1 | payload = p64(0xfbad3887)+p64(0)*3+p8(0) //这样写的话打印的就是_IO_2_1_stdin_ |
例题
这里就以这道iscc的题目作为例题讲解一下,是保护全开的一道题。
程序大致逻辑就是这样,所以现在我们就是想怎么把堆块分配到stdout的_IO_FILE结构体上了,我这里是先申请并释放7个0xf0的堆块占满tcache,再申请并释放几个0x50的小堆块控制一下堆块地址,保证我们要覆盖的next指针和我们接下来被释放进unsortdedbin的大堆块只有低1字节不同,这里的libc是2.31版本,并没有对tcache中的next指针进行加密,所以我们完全可以直接覆盖低1字节去打tcache poisoning,随后再对unsortedbin的fd的低2字节爆破,爆破被改为stdout,这样就能通过申请0x50的堆块申请到stdout指向的_IO_2_1_stdout_了,再利用它泄露libc地址,heap地址之类的,就能打通了。
不过这题因为seccomp_rule_add函数,会分配和释放很多堆块,导致堆块初始很乱,所以堆风水构建起来比较麻烦,需要费一点时间。
exp
1 | from pwn import * |








