Linux Polkit本地权限提升漏洞处理(CVE-2021- 4034)

一、背景

  安全部门近期发出安全预警,提示:常见发现版本的 CentOS、Ubuntu及Debian Linux系统中默认安装的Polkit工具集存在本地权限提升的漏洞CVE-2021- 4034),目前漏洞利用代码已在互联网公开;

   Linux Polkit工具集是Linux系统在安装过程中自带的系统工具集,其中包括大量运维常用工具。该工具集中的pkexec在特定情况下无法正确处理调用参数计数,因此会尝试将环境变量作为命令执行。攻击者可以通过控制环境变量,使自身从系统普通用户权限提升至管理员权限,对主机安全造成严重威胁。

本地环境:centos 7.8 2003

二、受影响版本

目前主流Linux版本均受影响。以下polkit版本为对应操作系统的修复版本:

1)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

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

三、检测方法

当前该漏洞利用脚本已被上传至Github,地址如下:
https://github.com/zhzyker/CVE-2021-4034
可使用该脚本检测本机是否存在漏洞,或检查漏洞是否修复完成。

git clone https://github.com/zhzyker/CVE-2021-4034.git
cd cve-2021-4034
gcc cve-2021-4034.c -o cve #普通用户下执行
./cve 'whoami'  #如果出现提升到root,则需要修复
./cve 'whoami&& uname -a'
rpm -qa|grep polkit #检查当前的版本

四、处理

目前各Linux发行版官方均已给出安全补丁,建议尽快升级至安全版本,如生产实际受限,我们可以采用官方提供的环节措施来处理。如下:

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

1)Redhat/Centos:

#1、根据提示,安装所需的 systemtap 包和依赖项
yum install systemtap systemtap-runtime -y

Installed:
  systemtap.x86_64 0:4.0-13.el7                                  systemtap-runtime.x86_64 0:4.0-13.el7                                 

Dependency Installed:
  boost-date-time.x86_64 0:1.53.0-28.el7                 dyninst.x86_64 0:9.3.1-3.el7              efivar-libs.x86_64 0:36-12.el7      
  kernel-debug-devel.x86_64 0:3.10.0-1160.53.1.el7       libdwarf.x86_64 0:20130207-4.el7          mokutil.x86_64 0:15-8.el7           
  systemtap-client.x86_64 0:4.0-13.el7                   systemtap-devel.x86_64 0:4.0-13.el7      

Complete!

#2、安装内核信息包:如果连外网直接运行stap-prep安装,否则请手动安装:kernel-debuginfo-内核版本号、kernel-debuginfo-common-内核版本号、kernel-devel--内核版本号;下载对应的三个rpm 包,地址http://rpm.pbone.net或http://debuginfo.centos.org/。注意不要直接yum install kernel-debuginfo kernel-debuginfo-common kernel-devel, 即使能找到相应的包,也是安装的最新版本,不会自动匹配当前版本。所以我们下载RPM包,再用rpm命令依次安装。
uname -r
3.10.0-693.11.6.el7.x86_64

wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-3.10.0-693.11.6.el7.x86_64.rpm

wget ftp://ftp.pbone.net/mirror/ftp.scientificlinux.org/linux/scientific/7.1/x86_64/updates/security/kernel-devel-3.10.0-693.11.6.el7.x86_64.rpm

wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-3.10.0-693.11.6.el7.x86_64.rpm

rpm -qa | grep kernel-debuginfo #centos7上如果安装或者升级到了最新的kernel-debuginfo包,会导致类似SystemTap这样需要内核头文件和调试符号的工具执行出错,先检查下
stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}' #没安装会提示
Checking "/lib/modules/3.10.0-693.11.6.el7.x86_64/build/.config" failed with error: No such file or directory
Incorrect version or missing kernel-devel package, use: yum install kernel-devel-3.10.0-693.11.6.el7.x86_64 

rpm -ivh kernel-debuginfo-common-x86_64-3.10.0-693.11.6.el7.x86_64.rpm
rpm -ivh kernel-debuginfo-3.10.0-693.11.6.el7.x86_64.rpm

Preparing...                          ################################# [100%]
	installing package kernel-debuginfo-3.10.0-693.11.6.el7.x86_64 needs 212MB on the / filesystem #如果根下空间不够,会安装失败,但不会提示
	
rpm -ivh kernel-devel-3.10.0-693.11.6.el7.x86_64

验证:
rpm -qa|grep kernel
kernel-debug-devel-3.10.0-1160.53.1.el7.x86_64
kernel-headers-3.10.0-862.el7.x86_64
kernel-debuginfo-common-x86_64-3.10.0-693.11.6.el7.x86_64
kernel-lt-5.4.148-1.el7.elrepo.x86_64
kernel-debuginfo-3.10.0-693.11.6.el7.x86_64
kernel-devel-3.10.0-693.el7.x86_64 #这个安装错了,应该是kernel-devel-3.10.0-693.11.6.el7.x86_64
kernel-3.10.0-693.11.6.el7.x86_64


stap -e 'probe begin{printf("Hello, World"); exit();}'
Checking "/lib/modules/3.10.0-693.11.6.el7.x86_64/build/.config" failed with error: No such file or directory
Incorrect version or missing kernel-devel package, use: yum install kernel-devel-3.10.0-693.11.6.el7.x86_64 
#/lib/modules/3.10.0-693.11.6.el7.x86_64/build/下没有测试文件,这是因为kernel-devel安装错误造成的,重新安装,再次执行:

ERROR: module version mismatch (#1 SMP Wed Jan 3 18:09:42 CST 2018 vs #1 SMP Fri Jan 5 00:19:49 CST 2018), release 3.10.0-693.11.6.el7.x86_64
WARNING: /usr/bin/staprun exited with status: 1
Pass 5: run failed.  [man error::pass5]

修改/usr/src/kernels/3.10.0-693.11.6.el7.x86_64/include/generated/compile.h的#define UTS_VERSION "#1 SMP Wed Jan 3 18:09:42 CST 2018"
修改时间与上述一致。更改为:Fri Jan 5 00:19:49 CST 2018

因为中间生成的C文件和ko模块都是用的cache (蓝色标注的部分),我们把上面的cache文件删除,再重新运行,这次可以成功了。

rm /root/.systemtap/cache/ab/stap_ab5e5aad682b3e1a2bbda0079814bf06_1016.c
rm /root/.systemtap/cache/ab/stap_ab5e5aad682b3e1a2bbda0079814bf06_1016.ko

#再次执行:
stap -e 'probe begin{printf("Hello, World"); exit();}' #输出如下

Hello, World

ll /lib/modules/3.10.0-693.11.6.el7.x86_64/

lrwxrwxrwx  1 root root     43 Jan 23  2018 build -> /usr/src/kernels/3.10.0-693.11.6.el7.x86_64

#3、安装polkit 调试 info:
debuginfo-install polkit

Installed:
  expat-debuginfo.x86_64 0:2.1.0-8.el7                       glib2-debuginfo.x86_64 0:2.54.2-2.el7                                      
  glibc-debuginfo.x86_64 0:2.17-222.el7                      mozjs17-debuginfo.x86_64 0:17.0.0-10.el7                                   
  pam-debuginfo.x86_64 0:1.1.8-23.el7                        polkit-debuginfo.x86_64 0:0.112-5.el7                                      
  systemd-debuginfo.x86_64 0:219-30.el7_3.6                  yum-plugin-auto-update-debug-info.noarch 0:1.1.31-54.el7_8                 

Dependency Installed:
  glibc-debuginfo-common.x86_64 0:2.17-222.el7                                                                                          

Complete!
#4、创建以下 systemtap 脚本,并将其命名为 pkexec-block.stp:
cat >pkexec-block.stp << EOF 
probe process("/usr/bin/pkexec").function("main")  {
         if (cmdline_arg(1) == "")
                         raise(9);
 }
EOF
#5、将 systemtap 模块加载到正在运行的内核中:
stap -g -F -m stap_pkexec_block ./pkexec-block.stp
#6、验证模块加载是否成功
lsmod | grep -i stap_pkexec_block  //输出如下
stap_pkexec_block     257978  0 

#6、如果此后将 polkit 包更新到包含修复程序的版本后,可以通过运行以下命令删除 systemtap 生成的内核模块:
rmmod stap_pkexec_block

注:此缓解措施不适用于启用安全启动的系统,因为 SystemTap 需要外部编译服务器才能对生成的内核模块进行签名,将密钥注册到内核的密钥环中。

2)或直接升级polkit

yum update polkit -y

升级完成后为:polkit.x86_64 0:0.112-26.el7_9.1,而对CentOS 7:polkit-0.112-26.el7_9.1已满足要求。

pkexec --version //pkexec version 0.112

验证:
在这里插入图片描述
3)Ubuntu:

环境:Ubuntu 16.04.6 LTS //lsb_release -a

检查:dpkg -l|grep policykit
在这里插入图片描述
更新:apt-get install --only-upgrade policykit-1 -y
在这里插入图片描述

五、附录

查看切换我们的进程的 stap 脚本:

在这里插入图片描述
在这里插入图片描述
其中:vmstate结果里:in: The number of interrupts per second, including the clock.

每秒钟中断次数,包括时钟中断.

cs: The number of context switches per second.每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好.上下文切换会影响CPU的利用率.

dstat结果:cpu:hiq、siq分别为硬中断和软中断次数。
system:int、csw分别为系统的中断次数(interrupt)和上下文切换(context switch)。

注:如果测试的话,可借助压测工具,sysbench,sysbench是一款压力测试工具,可以测试系统的硬件性能,也可以用来对数据库进行基准测试;wget https://github.com/akopytov/sysbench/archive/1.0.zip -O “sysbench-1.0.zip”。

但是这2个命令看不出事谁导致的上下文频繁切换,这里借助如下脚本,它会每隔设定的时间打印出TOP 20切换最多的进程和他的pid:

#! /usr/bin/env stap
#name:cswmon.stp
#
 
global csw_count
global idle_count
 
probe scheduler.cpu_off {
    
    
  csw_count[task_prev, task_next]++
  idle_count+=idle
}
 
 
function fmt_task(task_prev, task_next)
{
    
    
   return sprintf("%s(%d)->%s(%d)",
                                task_execname(task_prev),
                                task_pid(task_prev),
                                task_execname(task_next),
                                task_pid(task_next))
}
 
function print_cswtop () {
    
    
  printf ("%45s %10s\n", "Context switch", "COUNT")
  foreach ([task_prev, task_next] in csw_count- limit 20) {
    
    
    printf("%45s %10d\n", fmt_task(task_prev, task_next), csw_count[task_prev, task_next])
  }
  printf("%45s %10d\n", "idle", idle_count)
 
  delete csw_count
  delete idle_count
}
 
probe timer.s($1) {
    
    
  print_cswtop ()
  printf("--------------------------------------------------------------\n")
}

执行脚本:stap cswmon.stp 5
在这里插入图片描述
从上图结果,就可以看到进程从哪里切换到哪里,并且发生了多少次, 最后一行,打印出来idle的次数,也就是说这时候系统没啥事情做,就切换到idle(0)这个进程去休息去了。

当运行一个 SystemTap 脚本的时候,SystemTap 会在脚本外构建一个内核模块,SystemTap 然后把这个内核模块加载进内核,允许它直接从内核提取指定的数据。

正常情况下,SystemTap 仅仅会运行在部署了 SystemTap 的系统上。这意味着,如果你想在 10 个系统上运行 SystemTap,你必须把 SystemTap 部署到所有的系统上。有时候,这可能既不可行也不理想。比如,公司政策禁止管理员在指定的机器上安装 RPM 包来提供编译和 debug 信息,从而防止 SystemTap 的部署。为了解决这一问题,SystemTap 允许你使用 Cross-instrumentation。Cross-instrumentation 是一个从一台计算机上的 SystemTap 脚本生成 SystemTap 测量模块并在另一台计算机上使用的过程。

eg:为 2.6.18-92.1.10.el5 (x86_64 架构) 的目标内核从一个名称为 simple.stp 的 SystemTap 脚本创建一个测量模块 simple.ko,使用以下命令:

#语法:stap -r kernel_version script -m module_name;kernel_version 涉及到目标内核的版本(在目标系统上通过 uname -r 命令输出),script 涉及到转换成测量模块的脚本,module_name 涉及测量模块要求的名称。
stap -r 2.6.18-92.1.10.el5 -e 'probe vfs.read {exit()}' -m simple
#上述命令会创建一个名为 simple.ko 的模块,为了使用这个测量模块,拷贝它到目标系统,然后在目标系统运行以下命令,加载模块:
staprun simple.ko  //主机系统必须与目标系统是相同的架构以及相同的 Linux 发行版

猜你喜欢

转载自blog.csdn.net/ximenjianxue/article/details/122804972
今日推荐