思路
p1ay2win 师傅的博客已经写得很详细了,这里就不赘述了,简单记录一下思路。
本题有两种思路。
思路一:伪造 vtable
整体思路
IO_FILE_PLUS 文件结构中有个 vtable 指针指向存储一些函数指针的 IO_jump_t 结构体,这些函数指针在 puts/printf 等输入输出过程中会被调用,我们只要将 vtable 中的指针都覆盖为 one_gadget ,这样在程序下次调用 puts 的时候就能拿 shell 。
具体步骤
- leak libc addr
- 通过分配 unsorted bin 再 free 掉的方式,在 fd 指针上踩出 main_arena 的地址, show 这个 chunk 的内容就能泄露 main_arena 地址,然后根据 main_arena 与 libc 的偏移计算 libc 的基址。
- chunk over
- 说白了就是堆风水,过程说起来有点复杂,具体可以参考 p1ay2win 师傅的博客。由于程序对 chunk 的 content 输入有限制,这步的目的就是通过堆风水排布造成堆块重叠,这样我们在一个 chunk 中输入 content 而能覆盖多个 chunk 的内容。
- fastbin attack
- 通过 fast bin attack 将 chunk 分配到 IO_2_1_stdin 处,这样我们就能控制 vtable 的指针。
- fake vtable
- 在堆中伪造 vtable , fake_vtable 中布置好 one_gadget ,通过上一步将 vtable 指针指向 fake_vtalbe。
- get shell
- 通过 puts 函数触发 vtable 里 one_gadget 指针的调用从而拿 shell。
思路二:orw 打印 flag
整体思路
程序在 while 循环结束后调用了 seccmop 函数禁用了 execv 系统调用,也就是在 while 结束后我们不能用 system("/bin/sh") 或者 one_gadget 拿 shell 。但是可以使用 open 、 read 、 write ,所以我们可以通过 open('flag') ,然后 read 将flag 读到内存某处,在 write 出来。
具体步骤
- leak libc addr
- 与思路一相同
- chunk over
- 与思路一相同
- fastbin attack
- 这里也是通过 fastbin attack 将 chunk 分配到 IO_2_1_stdout 处,不过这里不是为了控制 vtable 指针,而是控制 IO_FILE 中的数据来泄露栈地址,具体数据布置可以参考 p1ay2win 师傅的博客。
- leak stack addr
- Linux 中有个 environ 环境指针,它指向环境变量表的起始地址, 而环境变量表中存储着各环境变量字符串的地址,其中就有字符串是存储在栈上的,也就是说只要我们能够泄露这个字符串,就能泄露栈地址。然后通过步骤 3 泄露栈地址。
- get ret addr
- 动态调试,确认主函数的返回地址在栈上的地址与步骤 4 泄露的栈地址的偏移,计算得出返回地址在栈上的地址。
- input orw
- 与步骤 3 类似,再次使用 fastbin attack 分配 chunk 到 IO_2_1_stdin 处,控制 IO_FILE 的数据实现任意写,然后往栈上的返回地址写入 orw 。
- get flag
- 程序运行至主函数退出后就会调用 orw ,将 flag 打印出来。