最近这几天CVE-2021-4034漏洞爆出来以后,大家都在紧急修复,验证、补丁、测试、上线、通知用户,过年之前的这段时间不免又忙碌了一阵。
现在补丁已经上线,而且被用户接收验证了,我们的心里当然是放下了一块石头,终于有时间在统信UOS上就这个漏洞做一些更细致的研究和确认了。
本次漏洞利用的是polkit
里的pkexec
程序,而polkit
是桌面环境里广泛使用的DBus
进程间通讯机制所依赖的安全模块之一,因此这个漏洞的波及面确实还是挺大的。不过在桌面团队修洞的过程中,我们发现在缺省(未开启开发者模式)情况下,统信UOS是不受主流攻击方式所影响的。
原因其实也很简单,因为统信UOS的当前版本在缺省情况下就提供了应用软件的签名验证机制,也就是说,如果一个软件没有得到有效证书的签名,它实际上是无法上架到应用商店,而且即使被手工复制到了本地,也会因为文件没有有效证书的签名,无法被运行起来的,对应保护的文件不仅是可执行文件,也包括了动态链接库(即so文件)。
那为什么有了可执行文件与动态链接库的证书签名验证机制,CVE-2021-4034漏洞就难以被利用了呢?
这就要从CVE-2021-4034漏洞的利用原理分析一下了。
本漏洞主要被利用的包括以下几点:
pkexec
为suid
程序
- 当
argc
(命令行参数个数变量)为0时,pkexec
会读取argv[1]
变量,而由于Linux进程的内存布局中环境变量是紧接着命令行参数的,因此实际上会读取到第一个环境变量。
- 读取到
argv[1]
之后,若其不是以/
开头的(即不是绝对路径),则pkexec
会将其理解为相对路径,继而会在环境变量中查找PATH
变量,将其转换为实际路径。
- 若
PATH
环境变量包含一个攻击者可控的路径,则pkexec
转换后的实际路径将会是这个攻击者可控的路径下的一个子目录,则显然此实际路径也是攻击者可控的。
pkexec
会对argv[1]
赋值,将其修改为上述得到的实际路径,但是我们知道argv[1]
此时实际上指向的是pkexec
的第一个环境变量,也就是说,pkexec
将自己的第一个环境变量修改为这个实际路径了。pkexec
会在程序运行过程中调用g_printerr
函数,这个函数会在运行的时候按需载入GCONV_PATH
环境变量指向的路径下的gconv-modules
文件中写明的外部动态链接库(so),并运行其中的初始化函数gconv_init
。
这样,攻击者只需要:
第一步:在自己可控的目录下生成一个gconv-modules
文件,并将文件内容设置为指向某个so
文件。
第二步:在so
文件中实现gconv_init
函数,此函数主要就是生成一个root shell(由于pkexec默认开启SUID),而在so库的此函数中,设置当前进程用户的uid为0,即可提权到root用户。
第三步:调用pkexec
,而且在调用的时候通过命令行参数设置使得pkexec
得到的argc
为0,将环境变量中的第一个设置为非/
开头的一个相对路径,将环境变量中的PATH
变量的值设置为GCONV_PATH=
开头的字符串,使得对应的路径指向上述存储gconv-modules
文件的路径。
就可以最终获得一个root shell了。
其中第一步与第三步可以有多种方法实现,虽然常见的PoC给出的是可执行程序,但是也可以通过脚本施行攻击,但是第二步需要生成一个so文件,就是在这里,新生成的so文件因为没有有效证书签名,因此在缺省的统信UOS上无法被载入执行。
当然,除了使用gconv
的外挂插件之外,从理论上来说,也可以思考如何利用环境变量从pkexec
的外部载入程序,但是这个实施难度显然就更高了。
因此,我们也希望统信UOS的广大用户不要修改系统的缺省配置,因为统信UOS基于证书签名的应用治理机制确实能有效地保护系统的安全,规避安全风险。