FILE指针结构,glibc

本文探讨了glibc中FILE*指针被破坏导致segment fault的问题,通过gdbcore调试,展示了_IO_write_base等成员的错误指向,并提供了一段示例代码用于观察这些指针的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在glibc中,gdb core调试,显示FILE*指针内容(FILE写出现了core文件)

 

$1 = {_flags = 107276440, _IO_read_ptr = 0x3000000018 <Address 0x3000000018 out of bounds>, _IO_read_end = 0x2aea0006e9a0 "痍\006", 

  _IO_read_base = 0x2aea0006e8e0 "痍2045", _IO_write_base = 0x53305239 <Address 0x53305239 out of bounds>, 

  _IO_write_ptr = 0x35343032eaf0 <Address 0x35343032eaf0 out of bounds>, _IO_write_end = 0x2aea0006e9b0 "-", _IO_buf_base = 0x2aea0006e9f0 "[2014-03-24][23:41:45]", 

  _IO_buf_end = 0x2aea0006eaf0 "adfbc"..., _IO_save_base = 0x2 <Address 0x2 out of bounds>, _IO_backup_base = 0x2 <Address 0x2 out of bounds>, 

  _IO_save_end = 0x2aea000819c0 "\300\t\004", _markers = 0x0, _chain = 0x3, _fileno = 107625062, _flags2 = 56, _old_offset = 47184511166896, _cur_column = 59792, 

  _vtable_offset = 6 '\006', _shortbuf = "", _lock = 0x7fff599c0590, _offset = 5052268, __pad1 = 0x2aea0006e980, __pad2 = 0x2aea0006e9b0, __pad3 = 0x2aea0006ea18, 

  __pad4 = 0x2d26da68, __pad5 = 32, _mode = 453104, _unused2 = "\352*\000\000@\352\006\000\352*\000\000伴\006\000\352*\000"}

 

 

可以看到_IO_write_base 错误,因此该文件指针FILE已经被破坏。所以会出现segment fault错误。

通常_IO_write_base  与_IO_read_base都指向同一区域。

表示当前缓冲区的基地址。

 

0x2aea0006e9a0-0x2aea0006e8e0  = C0 = 192字节

 

下面这段程序打印地址:

 

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char* argv[])

{

    FILE *fp = fopen("test.txt","w");

    char s[32]={0};

    for(int i=0;i<100;i++)

    {

        sprintf(s,"%d=now\n",i);

 

        fprintf(fp,"%s",s);

        fprintf(fp,"_IO_read_base=%x\n",fp->_IO_read_base);

        fprintf(fp,"_IO_write_base=%x\n",fp->_IO_write_base);

        fprintf(fp,"_IO_buf_base=%x\n",fp->_IO_buf_base);

    }

    fclose(fp);

return 0;

}

 

 程序输出:

94=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

95=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

96=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

97=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

98=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

99=now

_IO_read_base=2315d000

_IO_write_base=2315d000

_IO_buf_base=2315d000

### Pwn中IO_FILE利用技术详解 IO_FILE结构体是C标准库中用于管理文件流的核心数据结构,其在glibc中的实现包含了一系列的函数指针,用于处理文件的读写操作。攻击者在发现二进制漏洞时,如果能够控制这些函数指针或其调用上下文,就可能实现任意代码执行。 #### IO_FILE结构体的基本组成 IO_FILE结构体在glibc中定义如下,包含了一系列用于管理文件读写状态的字段: ```c struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ char* _IO_save_base; /* Pointer to start of non-current get area. */ char* _IO_backup_base; /* Pointer to just before start of backup area. */ char* _IO_save_end; /* Pointer to just past end of backup area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; /* File descriptor. */ ... }; ``` 其中,`_flags`字段用于标识文件流的状态,而`_IO_read_ptr`、`_IO_read_end`等字段用于管理缓冲区。最重要的是,`_IO_FILE`结构体内部包含了一个`_IO_jump_t`结构指针,该结构体包含了多个函数指针,例如`_IO_underflow`, `_IO_overflow`, `_IO_xsgetn`, `_IO_seekoff`, `_IO_seekset`等,这些函数指针决定了文件流的具体操作逻辑[^1]。 #### IO_FILE利用技术的核心思想 在二进制漏洞利用中,攻击者通常通过堆溢出、UAF(Use-After-Free)等漏洞修改`_IO_FILE`结构体中的函数指针或其关联的`_IO_jump_t`虚表指针。一旦控制了这些指针,攻击者可以在程序调用如`fread`, `fwrite`, `fclose`等函数时触发任意代码执行。 一个典型的攻击场景是通过堆溢出覆盖`_IO_jump_t`指针,使其指向攻击者控制的内存区域。随后,当程序尝试调用某个文件操作函数(如`fread`)时,就会跳转到攻击者指定的地址执行代码。例如,攻击者可以将该指针修改为指向栈或堆中的shellcode,从而获得控制权[^2]。 #### 实际攻击步骤示例 1. **泄露堆地址**:通过某种方式(如堆喷射或信息泄露漏洞)获取堆的地址,以便构造`_IO_jump_t`结构体的伪造虚表。 2. **堆风水布局**:通过精心构造堆块的分配与释放,确保`_IO_FILE`结构体位于可控的堆块中。 3. **堆溢出修改虚表指针**:利用堆溢出漏洞将`_IO_jump_t`指针修改为指向攻击者控制的内存区域。 4. **构造伪造的虚表**:在可控内存区域中构造一个伪造的`_IO_jump_t`结构体,其中包含指向shellcode的函数指针。 5. **触发函数调用**:调用如`fread`, `fwrite`等函数,触发虚表中的函数指针,从而执行shellcode[^4]。 #### 防御机制与绕过策略 现代glibc版本中引入了多种保护机制,例如: - **Tcache防护**:限制了tcache链表的篡改,防止简单的tcache poisoning攻击。 - **虚表完整性检查**:某些glibc版本中加入了对`_IO_jump_t`虚表地址的合法性检查,防止其指向不可信区域。 - **地址空间随机化(ASLR)**:通过随机化堆、栈和虚表的基址,增加攻击者预测地址的难度。 攻击者通常需要结合多个漏洞(如信息泄露+堆溢出)来绕过这些防护。例如,在无PIE(Position Independent Executable)的环境中,攻击者可以通过泄露libc基址来计算虚表地址,从而精确构造伪造的`_IO_jump_t`结构体[^1]。 #### 实战案例 在Google CTF 2022的FILESTORE题目中,攻击者通过堆溢出漏洞结合tcache poisoning技术,实现了对`__free_hook`的劫持,并最终调用`system`函数获取shell。虽然该题目并未直接使用IO_FILE利用技术,但其核心思想(通过堆溢出修改关键函数指针)与IO_FILE攻击有异曲同工之妙[^1]。 #### 代码示例 以下是一个简单的伪造`_IO_jump_t`结构体的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> void shell() { system("/bin/sh"); } int main() { FILE *fp = fopen("testfile", "w+"); char *fake_jump_table = malloc(0x100); memset(fake_jump_table, 0, 0x100); // 构造伪造的_IO_jump_t结构体,其中_IO_OVERFLOW字段指向shell函数 void **vtable = (void **)fake_jump_table; vtable[3] = (void *)shell; // _IO_OVERFLOW // 修改_IO_jump_t指针指向伪造的虚表 void **file_ptr = (void **)fp; file_ptr[13] = fake_jump_table; // _IO_vtable_offset // 触发_IO_OVERFLOW调用 fprintf(fp, "This will trigger shell()\n"); return 0; } ``` 上述代码中,`fake_jump_table`模拟了一个伪造的`_IO_jump_t`结构体,其中`_IO_OVERFLOW`函数指针被指向`shell`函数。通过修改`_IO_vtable_offset`字段,使得`fp`指向该伪造的虚表。当调用`fprintf`时,会触发`_IO_OVERFLOW`函数指针,从而执行`shell`函数。 #### 攻击链总结 1. **堆溢出或UAF漏洞**:获取对`_IO_FILE`结构体的写权限。 2. **伪造虚表**:在可控内存区域构造伪造的`_IO_jump_t`结构体。 3. **劫持控制流**:修改虚表指针,使其指向伪造的结构体。 4. **触发函数调用**:调用标准I/O函数(如`fread`, `fwrite`)触发shellcode执行。 这种攻击方式在CTF比赛中常用于绕过常规的ROP链构造,尤其在没有足够gadget的情况下具有较高的实用性[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值