关键字:安全漏洞;网络安全;信息安全;漏洞挖掘;操作系统
1.引言:
国外Qualys安全团队披露了Linux系统Polkit中的pkexec组件存在的本地权限提升漏洞(CVE-2021-4034)。Polkit(原名PolicyKit)是一个用于在类Unix操作系统中控制系统范围权限的组件。它为非特权进程与特权进程通信提供了一种有组织的方式。还可以使用polkit以提升的权限执行命令,先使用命令pkexec,然后是要执行的命令(前提是具有root权限)。Polkit默认安装在各个主要的 Linux 发行版本上(诸如Ubuntu、Debian、Fedora等知名Linux发型版本),pkexec程序对传入参数未过滤,攻击者可以将环境变量bash作为命令执行,从而诱导 pkexec 执行任意代码,利用成功可导致非特权用户获得管理员root权限。
2.漏洞复现
我们首先利用Github开源POC完成了Linux操作系统的本地提权限攻击(LPE)。
漏洞复现环境是Kali-Linux-2021.2-vmware-amd64,pkexec版本为0.105,通过普通⽤户zhicrsec进⾏复现,获取到root权限,如图2所示。
下载EXP并且编译源代码:
3.漏洞分析
3.1 漏洞分析基础环境
实验使用的操作系统是Kali-Linux-2021.2-vmware-amd64 ,polkit源码版本:polkit-0.105,设置GDB汇编风格为Intel,set disassembly-flavor intel,设置gdb的SUID位,避免调试pkexec时执⾏到geteuid函数失败,报错“pkexec must be setuid root”,使用命令sudo chmod 4755 /usr/bin/gdb为GDB提高执行权限.
3.2 漏洞原理
3.2.1 argv中存在的漏洞
我们通过C程序中argc传参程序进行分析,通过GCC命令编译程序。
argc表示参数的个数,argv存放着具体的参数,argv[0]指向程序本身,
argv[1]指向第⼀个参数,argv[2]指向第⼆个参数,...,argv[argc]存放0 表示结束。
当我们在命令⾏中执⾏程序时,必须向argc传参,argc的取值⾄少为1,如果不传参数,argv[0]也要指向程序路径本身。而execve函数原型定义如下:
include<unistd.h>
int execve(const char pathname, char const argv[],char *const envp[]);
在特殊情况下,如使⽤execve来调⽤程序,并给 argv传值 NULL,则argc为0。
为了验证execve传参问题,即要验证argv与envp在内存分布是连续的。由此更改execve.c与test.c程序,并且通过gcc -g -O0 -o test test.c与gcc -g -O0 -o execve execve.c重新编译程序。
如图10所示,程序设定argc指为4,加上NULL,argc值为5,这里程序直接输出了10个值,显然是存在缓冲区溢出漏洞。通过此实验证明到argv与envp在内存上布局是连续的,envp内存空间紧跟argv内存空间后面。
3.2.2复现pwnkit.c与argv漏洞的利用
main
编译程序时提示, warning: implicit declaration of function ‘g_printerr’,因为g_printer函数是隐式函数,所以需要包含一个.h头文件,func.h内容为void g_printer(void);
如图14所示,此时成功运行新生成的test程序,运行run.sh,此时设定两个系统环境变量
运行run.sh程序,成功在本地获取一个新的普通用户权限。
在本实验中,当环境变量设置了CHARSET,且不为UTF-8时, g_printerr会进⾏编码转换,⽽转换的⽅法就是根据GCONV_PATH⾥的配置⽂gconv-modules的说明,调⽤ pwnkit.so,从⽽得到shell。此处的pwnkit.sh文件是由cve-2021-4034.sh文件联合cve-2021-4034.c与pwnkit.c编译得到。
3.2.3通过IDA对pwnkit.so层逆向分析
IDA打开pwnkit.so文件后,我们观察到以上两个程序使用了execve,_setgid,_exit,_setuid等几个关键函数。got段中定义的execve原型:
aPathUsrLocalSb db 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
执行shellcode汇编代码:
var_28 = qword ptr -28h
envp = qword ptr -20h
var_18 = qword ptr -18h
path = qword ptr -10h
var_8 = qword ptr -8
; __unwind {
push ebp;开辟新的栈桢
mov rbp,rsp
sub rsp,30h
mov [rbp+var_20],rdi;
lea rax,aBinsh ;准备写入’/bin/sh’
mov [rbp+path], rax
mov [rbp+var_8], 0
lea rax, aPathUsrLocalSb ; "PATH=/usr/local/sbin:/usr/local
mov [rbp+envp], rax
mov [rbp+var_18], 0
mov edi, 0 ; uid uid=0 设置uid权限
call _setuid
mov edi, 0 ; gid gid=0 设置gid权限
call _setgid
mov rax, [rbp+path]
lea rdx, [rbp+envp] ; envp
lea rcx, [rbp+path]
mov rsi, rcx ; argv
mov rdi, rax ; path
call _execve
mov edi, 0 ; status
call _exit
; } // starts at 113C
3.2.4探索SUID权限
当⼀个程序被设置了SUID权限,则其他⽤户执⾏该程序时,可以临时切换到程序所有者的权限去执⾏⼀些功能。因为涉及到权限变更,所以在执⾏操作系统⾃带的此类程序时需要被授权。
授权之后可以使用root权限。
编写程序main.c与func.h,并且使用gcc -g -O0 test main.c编译,sudo chmod 4755提升test执行权限为root级别。继续编辑新的bash环境变量。
分别以root与zhicrsec用户执行bash run.sh|grep AAAAA,用来判断环境变量导入情况。
通过实验可以知道,当以普通⽤户身份去执⾏所有者为root且具有SUID权限的程序时,GCONV_PATH、LD_PRELOAD 等不安全的环境变量并不会被引⼊。
3.2.3利用原理进行漏洞分析:
下载源代码poltik-0.105,在Linux上安装编译环境后编译。
通过./configure&&sudo make编译得到
通过以上的探索,我们不难发现”./pkexec bash”是正常用法,pkexec会进行授权,接着使用root权限运行bash命令。但我们可以跳过授权认证,直接在本地运行root命令。此时我们修改cve-2021-4034.c源代码,进行GDB调试阶段。从源码层面分析授权认证是如何被绕过的?
3.2.4:继续探索pkexec的授权认证是如何被绕过的
用命令source set_trace.py,编写bplist GDB辅助调试程序。
gdb./pkexec -x bplist调试代码,GDB代码停在了705行,需要进行身份验证。
pkexec.c 705行验证身份程序如下:
result=polkit_authority_check_authorization_sync(authority,subject,action_id,details,POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,NULL,&error);
通过GDB调试发现,我们向系统更改path,将path设置成”GCONV_PATH=./pwnkit.so:.”再将path传如argv[1]中,接下来构造错误调用g_printerr函数,触发漏洞利用,最后执行execve("/bin/sh", args, environ)。完成未经授权代码执行。
process 11852 is executing new program: /usr/bin/dash
Error in re-setting breakpoint 1: Function "main" not defined.
Error in re-setting breakpoint 2: No source file named /home/kali/software/release/polkit-
0.105/src/programs/pkexec.c.
whoami
root
3.3 漏洞复现与分析总结
本次实验通过从argc危险传参操作,再到系统变量分析与源代码调试,我们发现了当使⽤普通⽤户权限执⾏pkexec时,GCONV_PATH、LD_PRELOAD等不安全的环境变量会被删除,攻击者可以通过参数数组的越界读写漏洞,重新引⼊不安全的环境变量,进⽽构造利⽤链获取root权限。CVE-2021-4034漏洞是程序设计者未考虑到的参数问题,由于pkexec大部分代码开源,并且由C语言编写,
可以让攻击者通过源码调试的方式找到漏洞。LPE漏洞风险较低,但也需要我嫩引起重视,防止RCE的出现。