RW Any Memory的全称是Read and write any memory, 就是内存任意读写;通常这种类型的漏洞是由于越界读写或者错误引用了指针操作造成可以修改控制某个区域里面的指针,导致我们可以改变程序的常规读写区域甚至程序执行流程.... 这里我是利用2019 STARCTF里面的hackeme来演示和学习这种漏洞的利用,其中环境和题目我放在github 上面了.需要的话可以自行下载学习....
modprobe_path指向了一个内核在运行未知文件类型时运行的二进制文件;当内核运行一个错误格式的文件的时候,会调用这个modprobe_path所指向的二进制文件去,如果我们将这个字符串指向我们的自己的二进制文件,那么在发生错误的时候就可以执行我们自己二进制文件了.... 这里modprobe_path的地址可以通过cat直接查看到:
原理代码如下,其实就是调用了call_usermodehelper
函数:
mod_tree是一块包含了模块指针的内存地址的内核地址,通过查看这个位置我们可以获取到ko文件的地址,在我们需要泄露模块基地址,但是在堆或栈中没有找到的时候可以查看这块内存区域:
首先我们看到这个hackme.ko文件开始传参大小为0x20
: 通过分析我们得出ko文件通过一个数据结构heap作为交互接口:
程序主要有4个功能:读,写,删除和申请:
主要是通过用户输入的长度,从用户态中写相应长度的数据到内核;
从内核中读出相应长度的数据到用户态;
这个代码主要是删除pool中的内容;
申请一块内存,地址和大小放在pool
数组中; 所以整个程序的功能就是维护了一个全局数组pool
,其第一个成员记录内核堆地址,第二个成员记录堆的大小,并且这个数组位于驱动的.bss段,这个我们可以通过gdb调试得出: 所以比较明显的漏洞点:在cin_kernel
和cout_kernel
功能中存在明显的越界问题,当我们的offset
是负数的时候,v17.offset + v17.len
就可以向上越界读写任意长度的内存;
因为slub
分配器的分配原理之前提过,和fastbin
的原理比较像,所以我们可以通过越界读写把pool
数组的位置申请下来,那么我们就可以控制pool
数组,然后将数组上面的指针改为其他地方的地址,那么我们就可以实现任意地址读写了;
因为我们可以堆地址往上越界读取数据,所以在堆地址上面的地址中一定存在有内核地址,而我们发现往上面偏移0x200
的位置就存在有内核地址: 很明显这是应该内核地址,所以我们可以得到内核基地址并且得到mod_tree
的地址:
根据fastbin
的特点,我们知道fd
指针指向下一次我们可以申请的地址,如果我们将fd
指针修改了,我们就可以拿到我们想要的内存了,同理我们这里也是通过覆盖fd
指针为mod_tree
的地址,然后就可以查看mod_tree
的内容然后就可以得到模块地址了: 覆盖fd
指针的方法是先通过向上越访问就可以修改到fd
指针,然后alloc
两个块,就可以拿到mod_tree
了:
需要注意的是不要把mod_tree
地址开始的位置全部覆盖了,应该往下偏移一定的位置,不然我们就得不到模块基地址了,有了模块基地址后我们就可以得到pool
的地址了,就可以利用同样的方法把pool
申请下来,然后我们就有任意地址读写的能力了;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-10-19 14:13
被钞sir编辑
,原因: 格式问题