首页
社区
课程
招聘
[原创]Linux Kernel Exploit 内核漏洞学习(4)-RW Any Memory
发表于: 2019-8-28 21:37 8837

[原创]Linux Kernel Exploit 内核漏洞学习(4)-RW Any Memory

2019-8-28 21:37
8837

RW Any Memory的全称是Read and write any memory, 就是内存任意读写;通常这种类型的漏洞是由于越界读写或者错误引用了指针操作造成可以修改控制某个区域里面的指针,导致我们可以改变程序的常规读写区域甚至程序执行流程....
这里我是利用2019 STARCTF里面的hackeme来演示和学习这种漏洞的利用,其中环境和题目我放在github上面了.需要的话可以自行下载学习....

modprobe_path指向了一个内核在运行未知文件类型时运行的二进制文件;当内核运行一个错误格式的文件的时候,会调用这个modprobe_path所指向的二进制文件去,如果我们将这个字符串指向我们的自己的二进制文件,那么在发生错误的时候就可以执行我们自己二进制文件了....
这里modprobe_path的地址可以通过cat直接查看到:

modprobe_path
原理代码如下,其实就是调用了call_usermodehelper函数:

mod_tree是一块包含了模块指针的内存地址的内核地址,通过查看这个位置我们可以获取到ko文件的地址,在我们需要泄露模块基地址,但是在堆或栈中没有找到的时候可以查看这块内存区域:

mod_tree

首先我们看到这个hackme.ko文件开始传参大小为0x20:
send
通过分析我们得出ko文件通过一个数据结构heap作为交互接口:

heap
程序主要有4个功能:读,写,删除和申请:

cin_kernel
主要是通过用户输入的长度,从用户态中写相应长度的数据到内核;

cout_kernel
从内核中读出相应长度的数据到用户态;

delete
这个代码主要是删除pool中的内容;

alloc
申请一块内存,地址和大小放在pool数组中;
所以整个程序的功能就是维护了一个全局数组pool,其第一个成员记录内核堆地址,第二个成员记录堆的大小,并且这个数组位于驱动的.bss段,这个我们可以通过gdb调试得出:
pool
所以比较明显的漏洞点:在cin_kernelcout_kernel功能中存在明显的越界问题,当我们的offset是负数的时候,v17.offset + v17.len就可以向上越界读写任意长度的内存;

因为slub分配器的分配原理之前提过,和fastbin的原理比较像,所以我们可以通过越界读写把pool数组的位置申请下来,那么我们就可以控制pool数组,然后将数组上面的指针改为其他地方的地址,那么我们就可以实现任意地址读写了;

因为我们可以堆地址往上越界读取数据,所以在堆地址上面的地址中一定存在有内核地址,而我们发现往上面偏移0x200的位置就存在有内核地址:
5
6
很明显这是应该内核地址,所以我们可以得到内核基地址并且得到mod_tree的地址:

根据fastbin的特点,我们知道fd指针指向下一次我们可以申请的地址,如果我们将fd指针修改了,我们就可以拿到我们想要的内存了,同理我们这里也是通过覆盖fd指针为mod_tree的地址,然后就可以查看mod_tree的内容然后就可以得到模块地址了:
7
覆盖fd指针的方法是先通过向上越访问就可以修改到fd指针,然后alloc两个块,就可以拿到mod_tree了:

需要注意的是不要把mod_tree地址开始的位置全部覆盖了,应该往下偏移一定的位置,不然我们就得不到模块基地址了,有了模块基地址后我们就可以得到pool的地址了,就可以利用同样的方法把pool申请下来,然后我们就有任意地址读写的能力了;


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-10-19 14:13 被钞sir编辑 ,原因: 格式问题
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 5594
活跃值: (2168)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
good job!
2019-8-30 09:01
0
雪    币: 31
活跃值: (47)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持楼主继续更新
2019-9-9 21:19
0
雪    币: 265
活跃值: (586)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
![8](./8.png) 图片没出来
2019-10-14 17:15
1
游客
登录 | 注册 方可回帖
返回
//