漏洞分析与实战分享 | 深入探讨pkexec提权漏洞

2024-09-15 87 0

前言

在一次学习研究漏洞中碰到了一个Linux提权漏洞CVE-2021-4034,引起了我的兴趣,便开始对这个漏洞细节展开分析,在学习的同时,我也想借此与各位师傅一起分享我的学习成果,我将详细分析介绍这一漏洞的工作原理、影响范围及其复现步骤。希望通过本篇文章的分享,能够帮助读者更全面地理解这个漏洞的风险,以期提高读者在安全防护与漏洞利用方面的认知

漏洞背景

此漏洞位于pkexec这一重要的组件中,它是Polkit的一部分,通过SUID二进制文件执行特定任务。

pkexec:一个允许以其他用户身份执行特定程序的程序(SUID 二进制)

漏洞分析与实战分享 | 深入探讨pkexec提权漏洞插图

在QUALYS通告中,可以明确以下几点:

  • 当argc为0时触发该漏洞
  • argv和envp在内存中是连续的
  • 越界写操作使我们能够写入envp[0](引入一个新的环境变量)

因此,首先需要理解C语言中的参数是如何工作的:

  • argv:这是一个以空字符终止的字符串数组,其元素是传递给程序的命令行参数。当通过命令行执行时,第一个(0)参数是程序本身
  • argc:一个整数,表示传递给 main() 函数的参数数组 argv 的大小。数组 argv 的长度为 argc,且 argv[argc] == NULL
  • envp:这个参数为函数提供对程序环境变量的访问,例如PATH变量

了解漏洞

为了能够完整的学习该漏洞,我将使用Ubuntu 18.04(2021年中)默认版本的pkexec,版本号为 0.105。

从相应的库中获取源代码:

git -c http.sslVerify=false clone https://gitlab.freedesktop.org/polkit/polkit.git

git checkout tags/0.105

这个漏洞问题出在 pkexec.c文件中,特别是处理参数的for循环。这个 for 循环检查传递给 pkexec 的每个参数,代码如下:

for (n = 1; n < (guint) argc; n++)

{

if (strcmp (argv[n], "--help") == 0)

{

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;

}

opt_user = g_strdup (argv[n]);

}

else if (strcmp (argv[n], "--disable-internal-agent") == 0)

{

opt_disable_internal_agent = TRUE;

}

else

{

break;

}

}

如果我们传递的argc == 0会发生什么呢?由于n从1开始,for循环会立即终止,意味着n == 1。这样n的值会传播到537行的以下代码:

path = g_strdup (argv[n]);

g_strdup的目标将是envp[0],因为sizeof(argv) == 1,这个值为NULL(argv[0] == NULL)。

考虑到这一点,通过调用execve系统调用,我们能够控制argv[0]使其不再是程序名称,而是传递一个空数组。

为了理解这个参数处理,我做了一个微小的示例,使用了两个基本程序,彼此通过execve() 调用。

ubuntu@ubuntu:~/pwn/tests/args$ cat one.c

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char *argv[]){

printf("Value of argc: %d\n", argc);

char **s = argv;

while(*s != NULL){

printf("Value: %s\n", *s);

s++;

}

return 0;

}

ubuntu@ubuntu:~/pwn/tests/args$ cat two.c

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char *argv[]){

char *args[] = {NULL};

char *envp[] = {"1","2", NULL};

execve("./one", args,  envp);

return 0;

}

编译并运行这个示例,很容易注意到,与直接从 shell 调用程序相比,使用execve时envp[0]在我们的控制之下。

漏洞分析与实战分享 | 深入探讨pkexec提权漏洞插图1

重新引入环境变量

如我们所知,调用一个SUID二进制程序是特殊的,因为它会清理传递给它的环境变量,以避免使用诸如 LD_PRELOAD 环境变量的攻击,但这正是此漏洞的亮点。

在越界读取的循环之后,我们达到以下代码片段:

/* Now figure out the command-line to run - argv is guaranteed to be NULL-terminated, see

*

*  http://lkml.indiana.edu/hypermail/linux/kernel/0409.2/0287.html

*

* but do check this is the case.

*

* We also try to locate the program in the path if a non-absolute path is given.

*/


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

webpack打包站点,js文件名批量获取思路
加密对抗靶场enctypt——labs通关
【论文速读】| 注意力是实现基于大语言模型的代码漏洞定位的关键
蓝队技术——Sysmon识别检测宏病毒
内网渗透学习|powershell上线cs
LLM attack中的API调用安全问题及靶场实践

发布评论