利用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/#