前言
近期CVE-2021-3156(sudo堆栈溢出漏洞)
国外的Qualys 研究团队在 sudo 发现了堆溢出漏洞,sudo是一种几乎无处不在的非常实用程序,可用于大型 Unix 类操作系统(类似与windows的UAC功能,但是功能更加强大,它还允许用户使用其他用户的安全权限运行程序,不仅限于管理员哟)。
笔者立马去找了相关的信息,企图找到漏洞利用exp。
https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit
然后找到这篇文章,分析挺详细的,但是当我看到最后
我瞬间泪崩,我kuzi都脱了,你给我说不行?说好的分享精神嘞?
但是人家卖产品,也情有可原嗷。
自己去分析内核代码写exp,那肯定不可能的,没到达那个水准,又不是专业的,算了算了,专业的事就该专业的人去弄,国内的大佬们应该很快就能写出exp了
不过我有点气,朋友又给我发了一个CVE-2019-13272 内核提权的漏洞,顺利找到了exp。
漏洞危害
kernel 5.1.17之前版本中存在安全漏洞,该漏洞源于kernel/ptrace.c文件的ptrace_link没有正确处理对凭证的记录,攻击者可利用该漏洞获取root访问权限。
漏洞测试成功的版本:
-
Ubuntu 16.04.5 kernel 4.15.0-29-generic
-
Ubuntu 18.04.1 kernel 4.15.0-20-generic
-
Ubuntu 19.04 kernel 5.0.0-15-generic
-
Ubuntu Mate 18.04.2 kernel 4.18.0-15-generic
-
Linux Mint 19 kernel 4.15.0-20-generic
-
Xubuntu 16.04.4 kernel 4.13.0-36-generic
-
ElementaryOS 0.4.1 4.8.0-52-generic
-
Backbox 6 kernel 4.18.0-21-generic
-
Parrot OS 4.5.1 kernel 4.19.0-parrot1-13t-amd64
-
Kali kernel 4.19.0-kali5-amd64
-
Redcore 1806 (LXQT) kernel 4.16.16-redcore
-
MX 18.3 kernel 4.19.37-2~mx17+1
-
RHEL 8.0 kernel 4.18.0-80.el8.x86_64
-
Debian 9.4.0 kernel 4.9.0-6-amd64
-
Debian 10.0.0 kernel 4.19.0-5-amd64
-
Devuan 2.0.0 kernel 4.9.0-6-amd64
-
SparkyLinux 5.8 kernel 4.19.0-5-amd64
-
Fedora Workstation 30 kernel 5.0.9-301.fc30.x86_64
-
Manjaro 18.0.3 kernel 4.19.23-1-MANJARO
-
Mageia 6 kernel 4.9.35-desktop-1.mga6
-
Antergos 18.7 kernel 4.17.6-1-ARCH
当调用PTRACE_TRACEME时,ptrace_link函数将获得对父进程凭据的RCU引用,然后将该指针指向get_cred函数,问题就出在这,PTRACE_TRACEME获取父进程的凭证(内核还记录了跟踪器的凭据),那么就能以父进程的权限执行各种操作,如果一个低权限的用户获取了高权限的父进程,但是在linux中,ptrace是一种系统调用,也就是说你得先拥有root权限,才能用ptrace到其他进程,如果只是普通权限,只能ptarce到子进程(下面会在利用条件中说)。
static void ptrace_link(struct task_struct *child, struct task_struct *new_parent)
{
rcu_read_lock();
__ptrace_link(child, new_parent, __task_cred(new_parent));
rcu_read_unlock();
__ptrace_link(child, new_parent, current_cred());
}
研究人员概述的这样一个攻击场景:
涉及一个父进程,父进程创建一个子进程,这个子进程会再创建一个子进程。第一个子进程使用命令pkexec(用于以root身份运行程序),第二个子进程运行PTRACE_TRACEME,然后第一个子进程丢弃其权限(理解为降权,以前权限很高,然后被降了)。最终结果是父进程可以使用ptrace来控制第一个子进程,后者可以使用ptrace来控制第二个子进程 – 从而让攻击者获得对两个进程的控制权。
我们不妨来分析一下这个场景:(利用思路就是利用父子进程来获得root用户访问权限(凭据))
首先父进程fork出一个子进程,子进程1又fork出相对于它的子进程2,子进程1有着高权限(很牛逼,无所不能,我就是root),子进程二运行着PTRACE_TRACEME,后面真正的root看着子进程1不爽(你凭什么拥有和我一样的权限啊,你也不看看你什么身份),然后就把子进程1降权了,但是运行着PTRACE_TRACEME的子进程2悄悄的把子进程1高权限的凭证给记录下来了,然后我们通过父进程去ptrace子进程1,再去ptrace子进程2,因为子进程二记录着root的凭据,然后我们以此来执行root权限的任意代码。
exp中利用思路就是是直接让子进程1去执行带有PTRACE_TRACEME的Polkit的pkexec(很难理解,但是后面看了Polkit以及exp,好像又理解了)
我分析起来都感到很鸡肋,实际利用也是这样的,假定如果我们能控制父进程(父进程最先开始高权限,运行ptrace到子进程,然后被其子进程运行的PTRACE_TRACEME记录下来了父进程高权限的凭据,后面父进程被降权了),然后通过ptrace到子进程获得高权限凭据,然后执行代码。
如果了解过逆向工程的小伙伴,肯定对这个ptrace不陌生,因为这是反调试技术中的基础入门手段,虽然现在诸如代码虚拟化之类的其他防逆向技术已经很成熟了,但是ptrace仍然是一些商业软件产品中使用,也是我们入门反调试所必须的基础技术!
Ptrace 可以让父进程控制子进程运行,并可以检查和改变子进程的核心image的功能(Peek and poke 在系统编程中是很知名的叫法,指的是直接读写内存内容)。ptrace主要跟踪的是进程运行时的状态,直到收到一个终止信号结束进程,这里的信号如果是我们给程序设置的断点,则进程被中止,并且通知其父进程,在进程中止的状态下,进程的内存空间可以被读写。当然父进程还可以使子进程继续执行,并选择是否忽略引起中止的信号,ptrace可以让一个进程监视和控制另一个进程的执行,并且修改被监视进程的内存、寄存器等,主要应用于断点调试和系统调用跟踪,strace和gdb工具就是基于ptrace编写的!
ptrace在linux 反调试技术中的地位就如同nc在安全界的地位,瑞士军刀啊!
ptrace使用场景:
1.编写动态分析工具,如gdb,strace
2.反追踪,一个进程只能被一个进程追踪(注:一个进程能同时追踪多个进程),若此进程已被追踪,其他基于ptrace的追踪器将无法再追踪此进程,更进一步可以实现子母进程双线执行动态解密代码等更高级的反分析技术
3.代码注入,往其他进程里注入代码。
4.不退出进程,进行在线升级。
而ptrace_traceme就是告诉父进程就字面意思跟踪我吧。
描述:pkexec是linux左面freedestop上的验证程序,pkexec允许授权用户以PROGRAM其他用户身份执行。如果username未指定,则该程序将以管理超级用户root的身份执行,在默认情况下需要管理员授权。
值得注意的是:pkexec是直接带有PTRACE_TRACEME的Polkit
Polkit是什么?
是用于在类似Unix的操作系统中控制系统范围特权的组件,它为非特权进程提供了一种与特权进程进行通信的有组织方式。
漏洞利用代码中也是用的pkexec
1.找suid降权的程序(我们能控制的,如pkexec)
2.如果利用pkexec(利用条件为桌面的终端linux,通过SSH会话利用此漏洞不成功)
exp用的就是pkexec,为什么用pkexec,因为在pkexec涉及到降权的行为,感兴趣的可以自己查资料结合exp看看
1.父进程生成子进程1
2.子进程1生成父进程2
3.子进程1执行suid程序pkexec
4.子进程2运行ptrace_traceme
5.父进程修改子进程1内存,ptrace到子进程2然后再修改子进程2执行任意代码(子进程二为root权限)
exp地址:
gcc正常编译就行了
原文始发于微信公众号(Gamma实验室):CVE-2021-3156 sudo堆栈溢出漏洞预警