fastbin有一个特性,就是在申请堆块大于smallbin(x64下0x128)的时候会对fastbin进行整理,先放进unsorted bin再送进small bin。
其次scanf读入巨大数据的时候会申请一个堆块来缓存数据,并且读入”+”的时候会跳过用户输入。
拥有上述两个特点之后,就可以实现虽然只有fastbin,但是能leak出libc,这一招可以将fastbin变为smallbin。
根据题目在这之后我们就有了往任意地址上写一个\x00的效果。
scanf通过stdin的FILE结构暂存输入流,然后再输入到指定位置。
scanf实现的核心函数是_IO_new_file_underflow
这个函数:
当stdin->_IO_read_ptr大于等于stdin->_IO_read_end时,此函数会调用_IO_SYSREAD()在stdin->_IO_buf_base处读入stdin->_IO_buf_end - stdin->_IO_buf_base个字节,然后更新stdin->_IO_read_end的值
所以我们可以通过修改_IO_buf_base的末尾为\x00,实现对_IO_2_1_stdin_的部分修改,然后改为我们指定的地方,实现任意地址写。
不过要注意缓冲区_IO_read_ptr和_IO_read_end的情况。
在scanf检测到输入不合规则的时候,会将数据丢弃到缓冲区中,也就是_IO_read_ptr那里,所以我们需要getchar()清空缓冲区再进行第二次的任意地址写。
题目来自HITCTF2023 scanf
在申请巨大堆块时,malloc会先整理fastbin,放到smallbin里面,然后就可以从fd中读出一个libc地址
劫持 _IO_FILE 结构体的 _IO_buf_base 和_IO_buf_end 实现任意地址写