从CVE漏洞分析到安全防护复盘
最近这几天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基于证书签名的应用治理机制确实能有效地保护系统的安全,规避安全风险。