上次比赛出了个house of roman
思路的题,结果发现这个利用方式已经落后于时代了,当大家纷纷把这题秒了的时候,我顿时对自己产生了怀疑。所以记录一下。。。。
其实主要思路就是修改stdout
的flag
位为0xfbad1800
,并且将_IO_write_base
的最后一个字节改小,从而实现多输出一些内容,这些内容里面就包含了libc地址。
stdout泄露
为什么flag
要改成0xfbad1800,看源码:
puts
函数在源码中是由_IO_puts
实现的,而_IO_puts
函数内部会调用_IO_sputn
,结果会执行_IO_new_file_xsputn
,最终会执行_IO_overflow
1 | int |
可以看到_IO_do_write
是最后调用的函数,而_IO_write_base
是我们要修改的目标。
这里f->_flag & _IO_NO_WRITES
的值应该为0,为了不进入第一个if分支
同时使f->_flag &_IO_CURRENTLY_PUTTING
的值为1,为了不进入第二个if分支
_IO_do_write
函数的参数为:stdout结构体、_IO_write_base
和size
(由f->_IO_write_ptr - f->_IO_write_base
决定),而_IO_do_write
实际会调用new_do_write
,参数一样。
1 | static |
这里,_IO_SYSWRITE
就是我们的目标,这相当于write(fp,data,to_do)
。
_IO_SYSSEEK
只是简单的调用lseek
,但是我们不能完全控制fp->_IO_write_base - fp->_IO_read_end
的值,如果fp->_IO_read_end的值设置为0,那么_IO_SYSSEEK
的第二个参数值就会过大,如果设置fp->_IO_write_base = fp->_IO_read_end
的话,那么在其它地方就会有问题,因为fp->_IO_write_base
不能大于 fp->_IO_write_end
。所以这里要设置fp->_flags | _IO_IS_APPENDING
,避免进入else if 分支。
最终需要构造的fp-flags是这样的,才能绕过上面提到的分支。
1 | _flags = 0xfbad0000 |
所以通常将stdout的flags修改成0xfbad1800,将_IO_write_base改小,就可以造成libc的泄漏。