利用modprobe_path提权
前言
现常用的提权方式为commit_creds(prepare_kernel_cred(0)
去获得root
凭证后返回用户态执行system("/bin/sh")
。现有另一种方法,则是通过改写modprobe_path
完成提权操作。
modprobe_path
modprobe_path
中存储了一个名为modprobe
的程序
modprobe
是一个最初由Rusty Russell编写的Linux程序,用于向Linux 内核添加可加载内核模块或从内核中删除可加载内核模块。
并且modprobe_path
是存储在内核空间中的,因此若内核存在任意地址写的漏洞,可以通过向该地址写入值,从而修改modprobe_path
指向的程序。
接下来调试分析一下,什么时候modprobe_path
指向的程序会被执行。我们首先准备一个不符合标准的文件,即文件头任意生成。
1 |
|
将test
传到文件系统中,文件系统使用的是syzkaller
所提供的https://github.com/google/syzkaller
1 |
|
这里需要注意的是要给测试文件一个可执行的权限
在执行一个错误文件头的文件时,函数调用栈如下图。
我们从search_binary_handler
函数开始分析,这里推荐用https://elixir.bootlin.com/linux审计linux的源码,可以快速搜索定位到函数。
search_binary_handler
search_binary_handler
函数实际就是找到能够解析指定文件的模块,从而解析文件。
在list_for_each_entry
开始遍历模块
若找到会将point_of_no_return
标记为1,反之则没有找到
当遍历了所有模块都没有找到能够解析文件的模块,则会进入request_module
函数进行模块的加载
在进入该函数之前,会将bprm->buf
作为参数,而变量存储的是文件头的信息,因此模块的加载依靠的是文件头信息
request_module
request_module
是一个宏定义,实际为__request_module
函数
在该函数中实际也只是调用了call_modprobe
call_modprobe
在call_modprobe
函数中,会将modprobe_path
传递给argv[0]
,最后使用call_usermodehelper_setup
在用户空间中创建一个子进程,该函数创建的子进程会以root
身份进行运行,这也是为什么覆盖modprobe_path
,可以完成提权的原因。
改写modprobe_path流程
- 首先需要获得
modprobe_path
的地址
1 |
|
- 接着程序需要能够进行任意地址写,并利用任意地址写往
modprobe_path
写入需要执行的程序名 - 构造一个非法的文件头,如
ffffffff
,促使内核进入call_modprobe
函数
3kctf2021-echo
题目地址:https://github.com/h0pe-ay/Kernel-Pwn/tree/master/3kctf2021/echo
题目只提供了一个echo.c
的文件,出题者在内核中新增了一个系统调用,调用号为548。与常规的内核题目不一样,该题目只是新增了一个系统调用,而没有加载额外的模块。
跟普通题目一样,flag.txt
需要root
权限才能够进行读取。
start.sh
题目开启了smep
、smap
、kpti
以及kaslr
保护
1 |
|
题目分析
由于题目只提供了新的系统调用,因此需要从该调用作为切入进行漏洞的利用。虽然题目提供了任意地址写的功能,但是没办法进行ROP
的利用。因此该题需要使用改写modprobe_path
从而能够读取flag.txt
文件。
但是题目开启了KASLR
的保护并且没有泄露地址的方法,因此需要通过爆破法去猜出modprobe_path
的位置。这里需要注意的点是下标i
需要设置为unsigned long
,若设置为int
会发生溢出,可能就无法覆盖到modprobe_path
的位置了。
我们还需要构造两个文件,一个是/tmp/p
文件,该文件是一个shell
文件,文件内容为读取flag.txt
的内容并放置在/tmp/flag
,第二个则是非法文件头的文件,将文件头构造为ffffffff
,去触发call_modprobe
函数的调用。这里需要注意的点是这两个文件都需要赋予执行权限。
当改写完成后在执行/tmp/exec
,此时内核会进入call_modprobe
函数,通过调用call_usermodehelper_setup
函数,在用户空间中新建一个子进程,该进程为modprobe_path
中指向的文件。运行完exp
可以发现modprobe_path
的指向被修改为/tmp/p
exp
完整exp
如下
1 |
|
参考链接
https://github.com/MaherAzzouzi/3k21-pwn/tree/main/echo
https://lkmidas.github.io/posts/20210223-linux-kernel-pwn-modprobe/#