这道题证明了,逻辑简单的题目利用很困难(逻辑复杂的题逆向又很困难ORZ
程序的逻辑很简单,三个功能:alloc,edit和delete。没有输出。本题控制了最多能申请三个块。
alloc函数,申请一个0x40大小的块,并输入内容。
edit函数,修改块中的内容。
delete函数,存在一点问题,如果没有输入'y',就不对notes[i]置零,存在UAF/double free漏洞。
delete函数中的UAF、double free漏洞。另外,给的libc版本是2.27,也就是bins中使用了tcache。虽然有UAF但是没有输出,所以泄露地址变得困难。
释放一个块同时到unsortedbin和tcache中,释放到unsorted bin中的目的是获取libc相关的地址,释放到tcache则是为了利用类似于fastbin attack来修改FD指针。至于如何得到一个unsortedbin,稍稍有些复杂,思路就是在堆上伪造一个块,并能够操作size字段,使之size为0x91,然后释放7次该块,填满0x90大小的tcache。然后修改该块的大小为0x51,释放到tcache 0x50中,再修改块大小为0x91,释放时就能放入到unsorted bin中。这样,这个block既在unsortedbin里又在tcache里。
由于main_arena+88是libc中的地址,通过修改最后两字节能够修改tcache中FD的指向,但只有最后1.5个字节是固定的,剩下的0.5个字节就需要碰运气了。
新学到的一个思路:如果能够修改libc中stdout的_IO_write_base
的值,由于puts会调用_IO_FILE_plus->vtable
中的函数,从_IO_write_base
中读数据。因此修改FD指向stdout,通过类似于fastbin attack的操作,将stdout这块交由用户输入,从而修改_IO_write_base
这里要补充一些关于puts函数的知识。在调用puts函数时,通过vtable调用了_IO_new_file_xsputn
函数:
函数先调用_IO_OVERFLOW
用于flush buffer,动态调试时可以看见对应的函数为_IO_new_file_overflow
。正常情况下,IO_FILE中的_IO_read_XXX
,_IO_write_XXX
,_IO_buf_XXX
指针的值比较相近,除了_IO_buf_end
剩下的指针值都相同。(这个是我观察的,如果不对欢迎指正!)所以在下面的函数中,调用_IO_do_write
读取从_IO_write_base
到_IO_write_ptr
的内容并没有输出,因为二者的值是相同的。
接着会调用new_do_write函数。block_size = f->_IO_buf_end
- f->_IO_buf_base
=1,则do_write = to_do= n。
在new_do_write中调用_IO_SYSWRITE,向fp中输出data(上面的s)中的to_do(上面的do_write)个字符。
总结一下,也就是正常使用时,_IO_write_ptr
和_IO_write_base
的值是相等的,调用_IO_OVERFLOW
也不会输出内容,接着执行_IO_SYSWRITE
输出data,也就是puts的参数。
但是如果我们能够修改_IO_write_base
中的值,使它指向想要泄露的地址,那么在_IO_OVERFLOW
中就能输出内容。
_IO_do_write
也是通过new_do_write
实现的。为了通过该方法进行泄露,对一些值进行设置,绕过new_do_write
里一些不需要的流程。
参考了vigneshsrao 的思路,观察_IO_new_file_overflow
和new_do_write
:
绕过_IO_new_file_overflow
中的 if (f->_flags & _IO_NO_WRITES
)
防止在执行 _IO_do_write
之前返回,其中_IO_NO_WRITES
为0x8
绕过_IO_new_file_overflow
中的if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
防止对我们设置好的指针进行重新赋值,使(f->_flags & _IO_CURRENTLY_PUTTING)
==1,_IO_CURRENTLY_PUTTING
为0x800
绕过new_do_write
中的 else if (fp->_IO_read_end != fp->_IO_write_base)
防止在执行_IO_SYSWRITE
之前return。vigneshsrao中给出的方法是,干脆不走这个else if,直接走上面的if (fp->_flags & _IO_IS_APPENDING)
,其中_IO_IS_APPENDING
=0x1000。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-1-28 16:28
被oguri编辑
,原因: 发现错误