[GKCTF2020]Domo

思路

p1ay2win 师傅的博客已经写得很详细了,这里就不赘述了,简单记录一下思路。
本题有两种思路。

思路一:伪造 vtable

整体思路

IO_FILE_PLUS 文件结构中有个 vtable 指针指向存储一些函数指针的 IO_jump_t 结构体,这些函数指针在 puts/printf 等输入输出过程中会被调用,我们只要将 vtable 中的指针都覆盖为 one_gadget ,这样在程序下次调用 puts 的时候就能拿 shell 。

具体步骤

  1. leak libc addr
    • 通过分配 unsorted bin 再 free 掉的方式,在 fd 指针上踩出 main_arena 的地址, show 这个 chunk 的内容就能泄露 main_arena 地址,然后根据 main_arena 与 libc 的偏移计算 libc 的基址。
  2. chunk over
    • 说白了就是堆风水,过程说起来有点复杂,具体可以参考 p1ay2win 师傅的博客。由于程序对 chunk 的 content 输入有限制,这步的目的就是通过堆风水排布造成堆块重叠,这样我们在一个 chunk 中输入 content 而能覆盖多个 chunk 的内容。
  3. fastbin attack
    • 通过 fast bin attack 将 chunk 分配到 IO_2_1_stdin 处,这样我们就能控制 vtable 的指针。
  4. fake vtable
    • 在堆中伪造 vtable , fake_vtable 中布置好 one_gadget ,通过上一步将 vtable 指针指向 fake_vtalbe。
  5. 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 出来。

具体步骤

  1. leak libc addr
    • 与思路一相同
  2. chunk over
    • 与思路一相同
  3. fastbin attack
    • 这里也是通过 fastbin attack 将 chunk 分配到 IO_2_1_stdout 处,不过这里不是为了控制 vtable 指针,而是控制 IO_FILE 中的数据来泄露栈地址,具体数据布置可以参考 p1ay2win 师傅的博客。
  4. leak stack addr
    • Linux 中有个 environ 环境指针,它指向环境变量表的起始地址, 而环境变量表中存储着各环境变量字符串的地址,其中就有字符串是存储在栈上的,也就是说只要我们能够泄露这个字符串,就能泄露栈地址。然后通过步骤 3 泄露栈地址。
  5. get ret addr
    • 动态调试,确认主函数的返回地址在栈上的地址与步骤 4 泄露的栈地址的偏移,计算得出返回地址在栈上的地址。
  6. input orw
    • 与步骤 3 类似,再次使用 fastbin attack 分配 chunk 到 IO_2_1_stdin 处,控制 IO_FILE 的数据实现任意写,然后往栈上的返回地址写入 orw 。
  7. get flag
    • 程序运行至主函数退出后就会调用 orw ,将 flag 打印出来。

参考

[PWN]GKCTF 2020 Domo分析

原文地址:https://www.cnblogs.com/luoleqi/p/13462383.html