1. 新版本libc下IO_FILE的利用
1.1 介绍
在最新版本的glibc中(2.24),全新加入了针对IO_FILE_plus的vtable劫持的检测措施,glibc 会在调用虚函数之前首先检查vtable地址的合法性。
如果vtable是非法的,那么会引发abort。
首先会验证vtable是否位于_IO_vtable段中,如果满足条件就正常执行,否则会调用_IO_vtable_check做进一步检查。
这里的检查使得以往使用vtable进行利用的技术很难实现
1.2 新的利用技术
在vtable难以被利用之后,利用的关注点从vtable转移到_IO_FILE结构内部的域中。 前面介绍过_IO_FILE在使用标准IO库时会进行创建并负责维护一些相关信息,其中有一些域是表示调用诸如fwrite、fread等函数时写入地址或读取地址的,如果可以控制这些数据就可以实现任意地址写或任意地址读。
|
|
因为进程中包含了系统默认的三个文件流stdin\stdout\stderr,因此这种方式可以不需要进程中存在文件操作,通过scanf\printf一样可以进行利用。
在_IO_FILE中_IO_buf_base表示操作的起始地址,_IO_buf_end表示结束地址,通过控制这两个数据可以实现控制读写的操作。
1.3 示例
简单的观察一下_IO_FILE对于调用scanf的作用
|
|
在执行程序第一次使用stdin之前,stdin的内容还未初始化是空的
|
|
调用scanf之后可以看到_IO_read_ptr、_IO_read_base、_IO_read_end、_IO_buf_base、_IO_buf_end等域都被初始化
|
|
进一步思考可以发现其实stdin初始化的内存是在堆上分配出来的,在这里堆的基址是0x602000,因为之前没有堆分配因此缓冲区的地址也是0x602010
|
|
分配的堆大小是0x400个字节,正好对应于_IO_buf_base~_IO_buf_end 在进行写入后,可以看到缓冲区中有我们写入的数据,之后目的地址栈中的缓冲区也会写入数据
|
|
接下来我们尝试修改_IO_buf_base来实现任意地址读写,全局缓冲区buf的地址是0x7ffff7dd2740。修改_IO_buf_base和_IO_buf_end到缓冲区buf的地址
|
|
之后scanf的读入数据就会写入到0x7ffff7dd2740的位置
|
|