小论文改得蛋疼,看个Pwn缓解下心情。(家里上Github真的慢…怀念北邮的网速)
参考:
https://teamrocketist.github.io/2020/02/05/Pwn-HackTM-2020-Trip-To-Trick/
https://www.slideshare.net/AngelBoy1/play-with-file-structure-yet-another-binary-exploit-technique
一个经常出的类型的Pwn题,但是环境用了最新的libc-2.29,因此做个记录。
0x00 概述
- 已知libc地址
- 两次
scanf
任意地址写8字节数据 - return前关闭
stdin
、stdout
和stderr
- 有沙箱
0x01 思路
- 第一次
scanf
将_IO_2_1_stdin_
的_IO_BUF_END
设置为STDIN+0x2000 - 第二次
scanf
就可以控制_IO_FILE的结构 - 将STDOUT的
vtable
设置为_IO_helper_jumps
,flags
设置为0来绕过检查 - 在libc-2.29中,
vtable
是可写的,因此通过控制_IO_helper_jumps->__finish
来劫持控制流 - 设置_IO_helper_jumps的__finish为setcontext+0x35
- 构造ORW的ROP Chain
0x02 一些程序分析
沙箱
1 | line CODE JT JF K |
vtable
在libc-2.29中,vtable区域又重新拥有可写的权限,因此出题人通过nohack函数进行了限制:
1 | int nohack() |
但是下列vtable仍然可写:
_IO_helper_jumps
_IO_cookie_jumps
_IO_proc_jumps
_IO_str_chk_jumps
_IO_wstrn_jumps
_IO_wfile_jumps_maybe_mmap
利用其中的函数指针可以控制RIP。
缓冲区
1 | int main_init() |
Pwn题的基本操作,将缓冲区置0,std将不会使用缓冲区。_IO_buf_base
和_IO_buf_end
的差值只有1,会使得stdin只能存储一个字节在缓冲区,即回车或空字符(取决于输入形式)。
如果我们通过第一次scanf增加了stdio->_IO_buf_end
的值,将能控制vtable。
除了修改stdout->vtable
为_IO_helper_jumps
和修改_IO_helper_jumps
中的函数指针外,中间经过的大片内存区域也需要修复而不是简单的进行零填充。