首页
社区
课程
招聘
[原创]Linux Kernel Exploit 内核漏洞学习(2)-ROP
发表于: 2019-7-27 20:09 16069

[原创]Linux Kernel Exploit 内核漏洞学习(2)-ROP

2019-7-27 20:09
16069

ROP的全称为Return-oriented Programming,主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程;这种攻击方法在用户态的条件中运用的比较多,ret2shellcode,ret2libc,ret2text等ret2系列都利用到了ROP的思想,当然这种攻击手法在内核态同样是有用的,并且手法都基本一样....
这里我以2018年的强网杯中的core来进行演示和学习的,环境我已经放到的了github上面了,需要的可以自行下载学习....

我们知道Linux操作系统中用户态和内核态是相互隔离的,所以当系统从内核态返回到用户态的时候就必须要进行一些操作,才可以是两个状态分开,具体操作是:

现在我们可以先分析一下这个core.ko驱动了:
首先查看一下这个ko文件的保护机制有哪些:
checksec
开启了canary保护....
core_ioctl:
core_ioctl
这个函数定义了三条命令,分别调用core_read(),core_copy_func(),并且可以设置全局变量off;
core_copy_func:
core_copy_func
这个函数会根据用户的输入长度,从name这个全局变量中往栈上写数据,并且函数在判断我们输入的这个a1变量类型的时候是signed long long,但是qmemcpy的时候就变成了unsigned __int16了,所以这里存在一个截断,当我们输入如0xf000000000000000|0x100这样的数据就可以绕过限制,就可以造成内核的栈溢出了;
core_read:
core_read
这个函数会从栈上读出长度为0x40的数据,并且读的起始位置我们可以通过改变off这个全局变量的大小来控制,也就是说这个我们可以越界访问数据,将栈上面的返回地址,canary等信息读到....
core_write:
core_write
最后这个函数我们可以向全局变量name中写入一个长度不大于0x800的字符串....

所以现在我们思路比较清晰了:

用户态起shell,get root;
所以这里最重要的就是我们的ROPchain的构造了....
为了方便调试,我们修改一下init文件:

这样我们start的时候就是root权限了,方便我们查看一些函数的地址;

首先我们查看一下qume中函数的地址:
qemu
然后通过gdb调试查看core_read的栈内容:
stack
基本我们能够从栈中泄露vmlinux和core.ko的基地址了....
通过这些位置的地址减去偏移就是基地址了,这个和在用户态找libc的基地址的方法是一样的,所以就不过多解释了.....
然后我们可以利用ropper工具来查找我们需要的gadget了:

这里建议使用ropper而不是ROPgadget,因为ROPgadget太慢了,ropper可以直接通过pip install ropper来安装;
这里多说一点,其实有时候如果等待的时间是在太长了可以试试这个这样去找:

只是这样格式不是太好看,但是非常快....
我这里构造出来的rop链在代码中基本都体现出来了,所以直接看代码就好;
#EXP
poc.c:

编译:

运行:
root
这里说两个地方,第一个是确定填充的垃圾数据的大小时,可以利用gbd动态调试查看确定:
junk
确定填充的大小是0x40;
然后就是ROP链中有一个:

这里有一个pop_rcx_ret的原因是因为call指令的时候会把它的返回地址push入栈,这样会破坏我们的ROP链,所以要把它pop出去:
pop

最后这里在说另外一个方法也是基于ROP的方法;
因为这个内核开启了kalsr和canary,但是没有开启smep保护,我们可以利用在用户空间的进程不能访问内核空间,但是在内核空间能访问用户空间的特性,我们可以直接返回到用户空间构造的commit_creds(prepare_kernel_cred(0))(通过函数指针实现来提权,虽然这两个函数位于内核空间,但因为此时我们是ring 0特权,所以可以正常运行;

ret2usr.c:

编译:

运行:
ret2usr

可以发现这两个方法的代码非常的相似,因为原理都一样的....

这个演示看起来很简单,但是在实际的操作过程当中会遇到比较多的问题,在内核态调试没有在用户态方便,因为内核一旦崩溃了就会重启,所以崩溃的时候gdb不一定断的下来,只能通过单步跟踪来慢慢的定位问题....

 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-7-28 16:15 被钞sir编辑 ,原因:
收藏
免费 12
支持
分享
最新回复 (7)
雪    币: 73
活跃值: (923)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2019-7-29 11:38
0
雪    币: 32
活跃值: (17)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
3
请问一下,师傅你是如何找内核函数的偏移的?
2019-9-25 09:14
0
雪    币: 1506
活跃值: (4411)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4
rnaple 请问一下,师傅你是如何找内核函数的偏移的?
真实地址减去基地址就可以,和用户层找system函数等方法一样....
2019-9-25 15:57
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
ntr
5

师傅,我vm虚拟机下Ubuntu18.04跑的ropper,但ropper提取vmlinux下gedget会直接卡死在98%然后就输出killed,请问这是什么情况呢?

ps:是最新版本的ropper

最后于 2021-4-19 01:19 被ntr编辑 ,原因:
2021-4-19 01:18
0
雪    币: 1506
活跃值: (4411)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
6
ntr 师傅,我vm虚拟机下Ubuntu18.04跑的ropper,但ropper提取vmlinux下gedget会直接卡死在98%然后就输出killed,请问这是什么情况呢?ps:是最新版本的ropper
这个不太了解哎,你可以试试用        
objdump去找试试吧
2021-4-20 07:57
0
雪    币: 277
活跃值: (485)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
师傅,请教一下是否可以按照类似思路去调试安卓平板的驱动,并获取驱动文件内容?
2021-8-6 21:30
0
雪    币: 425
活跃值: (525)
能力值: ( LV4,RANK:48 )
在线值:
发帖
回帖
粉丝
yyp
8
为什么我在kali里运行的内核,起shell时出现Segmentation fault。但是ubuntu22.04里起shell却是正常的?
2023-9-13 18:54
0
游客
登录 | 注册 方可回帖
返回
//