小论文改得蛋疼,看个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中的函数指针外,中间经过的大片内存区域也需要修复而不是简单的进行零填充。