点击蓝字 关注我们
日期:2024.07.01 作者:H4y0 介绍:Linux_io_FILE基础知识。
0x00 前言
_IO_FILE
利用已成为CTF
中PWN
题的常规利用思路,逐渐成为基础知识,上篇文章已经介绍了_IO_FILE
的结构及标准I/O
流相关内容,本文将介绍vtable
及与vtable
相关的劫持程序流的方法。
0x01 伪造vtable
借用Wiki
上的例子:
int main(void)
{
FILE *fp;
long long *vtable_ptr;
fp=fopen("123.txt","rw");
vtable_ptr=*(long long*)((long long)fp+0xd8); //get vtable
memcopy(fp,"sh",3);
vtable_ptr[7]=system_ptr //xsputn
fwrite("hi",2,1,fp);
}
使用glibc-2.23
进行编译,glibc2.23
版本下,位于 libc
数据段的vtable
是不可以进行写入的,但是可以通过伪造vtable
并且修改_IO_FILE_plus->vtable
这个指针来实现劫持程序流程。
简单介绍一下fwrite
函数。
_IO_size_t
_IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
_IO_size_t request = size * count;
_IO_size_t written = 0;
CHECK_FILE (fp, 0);
if (request == 0)
return 0;
_IO_acquire_lock (fp);
if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)
written = _IO_sputn (fp, (const char *) buf, request);
_IO_release_lock (fp);
/* We have written all of the input in case the return value indicates
this or EOF is returned. The latter is a special case where we
simply did not manage to flush the buffer. But the data is in the
buffer and therefore written as far as fwrite is concerned. */
if (written == request || written == EOF)
return count;
else
return written / size;
}
libc_hidden_def (_IO_fwrite)
fwrite
是C
标准库中用于将数据块写入文件的函数,它通常是对底层文件 I/O
函数的封装之一。_IO_sputn
函数与 fwrite
的实现息息相关。在GNU C
库中,fwrite
函数通常会调用一系列与文件 I/O
相关的函数,其中包括 vtable
(虚函数表)函数。
-
_IO_fwrite 函数调用了 vtable 的 _IO_new_file_xsputn 。
-
_IO_new_file_xsputn 函数调用了 vtable 中的 _IO_new_file_overflow 实现缓冲区的建立以及刷新缓冲区。
-
vtable 中的 _IO_new_file_overflow 函数调用了 vtable 的 _IO_file_doallocate 以初始化输入缓冲区。
-
vtable 中的 _IO_file_doallocate 调用了 vtable 中的 __GI__IO_file_stat 以获取文件信息。
-
new_do_write 中的 _IO_SYSWRITE 调用了 vtable_IO_new_file_write 最终去执行系统调用write。
也就是说,fwrite
函数会用到xsputn
,vtable_ptr[7]=system_ptr //xsputn
这行代码将虚函数表中的第7
个函数指针(通常对应 xsputn
函数,可见上篇文章_IO_jump_t
)替换为 system
函数的地址,从而在运行fwrite
时运行system
函数,实现劫持程序流程。
0x02 IO_validate_vtable
IO_validate_vtable
是GNU C
库中的一个函数,用于验证文件结构体中的虚函数表是否有效。
static inline const struct _IO_jump_t *IO_validate_vtable(const struct _IO_jump_t *vtable) {
/* Fast path: The vtable pointer is within the __libc_IO_vtables
section. */
uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
uintptr_t ptr = (uintptr_t) vtable;
uintptr_t offset = ptr - (uintptr_t) __start___libc_IO_vtables;
if (__glibc_unlikely (offset >= section_length))
/* The vtable pointer is not in the expected section. Use the
slow path, which will terminate the process if necessary. */
_IO_vtable_check();
return vtable;
}
void attribute_hidden _IO_vtable_check(void) {
/* Honor the compatibility flag. */
void (*flag)(void) = atomic_load_relaxed (&IO_accept_foreign_vtables);
PTR_DEMANGLE (flag);
if (flag == &_IO_vtable_check)
return;
/* In case this libc copy is in a non-default namespace, we always
need to accept foreign vtables because there is always a
possibility that FILE * objects are passed across the linking
boundary. */
{
Dl_info di;
struct link_map *l;
if (!rtld_active()
|| (_dl_addr(_IO_vtable_check, &di, &l, NULL) != 0
&& l->l_ns != LM_ID_BASE))
return;
}
...
}
static inline bool rtld_active (void) {
/* The default-initialized variable does not have a non-zero
dl_init_all_dirs member, so this allows us to recognize an
initialized and active ld.so copy. */
return GLRO(dl_init_all_dirs) != NULL;
}
int _dl_addr(const void *address, Dl_info *info, struct link_map **mapp, const ElfW(Sym) **symbolp) {
const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
int result = 0;
/* Protect against concurrent loads and unloads. */
__rtld_lock_lock_recursive (GL(dl_load_lock));
...
其中rtld_active
函数通过检查通过检查 dl_init_all_dirs
变量是否非空来判断 ld.so
是否处于活动状态。如果返回true
,则调用_dl_addr
,进而执行__rtld_lock_lock_recursive (GL(dl_load_lock))
。而这个宏和exit hook
对应的宏一致,所以和exit hook
的思路一样,通过改写指针就可以实现劫持程序流。当然,同样在glibc2.34
之后__rtld_lock_lock_recursive
和 __rtld_lock_unlock_recursive
进行了修复,该劫持程序流的方式和exit hook
一同失效。
0x03 总结
vtable
劫持程序流,也可以通过IO_validate_vtable
使用和exit hook
相似的方式劫持程序流。往
期推荐
『CTF』堆入门 ➠
点此亲启
原文始发于微信公众号(宸极实验室):『CTF』IO_FILE利用入门(2)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论