利用_IO_FILE结构

参考《CTF竞赛权威指南(PWN篇)》
,ctf.wiki
https://blog.xmcve.com/2022/08/14/%E5%AD%A6%E4%B8%8D%E5%AE%8C%E7%9A%84IO/#title-2
1.FILE结构体
文章:https://www.yuque.com/yuqueyonghupiiwso/gixo00/bekmilyu3sn6sh3e?singleDoc# 《FILE结构》
可以参考上面写的文章,下面简单说一下吧。
FILE结构体
- FILE结构被被一系列流操作函数(fopen(),fread,fclose()等)所使用、大多数的FILE结构体保存在堆上(stdin,stdout,stderr除外,位于libc数据段),其指针动态创建并由fopen()函数返回。在libc的2.23版本中,这个结构体是
_IO_FILE_plus
,包含了一个_IO_FILE
结构体和一个指向_IO_jump_t
结构体的指针。
源码网址:https://elixir.bootlin.com/glibc/glibc-2.23/source/libio/libioP.h#L307
1 | struct _IO_jump_t |
- vtable指向的函数跳转表其实是一种兼容C++虚函数的实现。当程序对某个流进行操作时,会调用该流对应的跳转表中的某个函数。
1 | struct _IO_FILE { |
进程中的FILE结构通过_chain域构成一个链表,链表头部为_IO_list_all全局变量,默认情况下依次链接了stddrr、stdout和stdin三个文件流,并将新创建的流插入到头部。
另外,_IO_wide_data也是后面所需要的
1 | /* Extra data for wide character streams. */ |
2.FSOP
- FSOP(File Stream Oriented Programming)是一种劫持_IO_list_all(libc.so中的全局变量)来伪造链表的利用技术,通过调用_IO_flush_all_lockp()函数触发。该函数会在下面三种情况下被调用:
当libc检测到内存错误从而执行abort流程时;🤯
执行exit函数时;🤯🤯
当main函数返回时。🤯🤯🤯
- 当libc检查到内存错误时,会产生下面的函数调用路径
1 | malloc_printerr->_libc_message->_GI_abort->_IO_flush_all_lockp->_IO_OVERFLOW |
2.23版本
因此衍生出了FSOP
,通过伪造、_IO_jump_t中的_overflow
为system函数地址
,最终在_IO_OVERFLOW(fp,EOF)
函数中执行system(‘/bin/sh’)并获得shell。
_IO_jump_t是vtable虚表,由于2.23未对vtable进行检查,我们将其指向一个可写的地方,构造fake_vtable即可
1 | int _IO_flush_all_lockp (int do_lock) |
- 条件
1 | fp->_mode <= 0 |
还有一种是通过_IO_FINISH(fp)的时候来调用伪造的system(“/bin/sh”)
1 | int |
实操:
题目:http://downbeat.top/2024/10/08/House-Of-Orange
ctf-wiki上面的例子:
2.24版本
该版本加入了对vtable的检查,所有的vtables
都被放进了__libc_IO_vtables
段里面,使得他们在内存中连续,在任何跳转之前,vtable
指针都会调用IO_validate_vtable()
函数进行边缘检查,如果指针不在这个段,那么将会调用IO_vtable_check()
函数进一步检查。
1 | IO_validate_vtable (const struct _IO_jump_t *vtable) |
利用_IO_str_jumps
由于vtable增加了check,所以我们无法修改虚表指向_libc_IO_vtables以外的地方,因此我们得在__libc_IO_vtables里面找些有用的东西,比如说_IO_str_jumps
1 | const struct _IO_jump_t _IO_str_jumps libio_vtable = |
1.利用_IO_str_overflow
1 | int |
构造要求如下:
- fp->_flag = 0
- fp->_IO_write_ptr = 0xffffffffffffffff
- fp->_IO_write_base = 0
- fp->_IO_buf_end = (str_bin_sh - 100) / 2
注意:str_bin_sh最好是偶数,避免除法向下取整,可以+1
- fp->_IO_buf_base = 0
- fp->mode = 0
- fp + 0xe0 = system_addr
另外,system(“/bin/sh”)可以用ogg代替
1 malloc_printerr -> __libc_message -> __GI_abort -> _IO_flush_all_lockp -> __GI_IO_str_overflow
- 标题: 利用_IO_FILE结构
- 作者: D0wnBe@t
- 创建于 : 2024-12-05 14:53:51
- 更新于 : 2025-03-12 20:14:31
- 链接: http://downbeat.top/2024/12/05/利用-IO-FILE结构/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。