首页
社区
课程
招聘
[原创]CVE-2021-4034分析
发表于: 2023-8-16 21:57 12418

[原创]CVE-2021-4034分析

2023-8-16 21:57
12418

在 polkit 的 pkexec 工具中发现的本地权限升级漏洞。pkexec 应用程序是一个 setuid 工具,旨在允许非特权用户按照预定义策略以特权用户身份运行命令。当前版本的 pkexec 无法正确处理调用参数个数,并试图将环境变量作为命令执行。攻击者可以利用这一点,精心设计环境变量,诱使 pkexec 执行任意代码。成功执行后,该攻击可导致本地权限升级,赋予未授权用户在目标计算机上的管理权限。

漏洞代码(v0.120):

漏洞逻辑如下:

所以数组越界会取到envp[0]的值并赋值给path

所以漏洞可以做到一个越界写,解析出envp[0]在环境变量PATH中的路径,并将"路径/envp[0]"写回envp[0]

Linux下的目录中可以带有特殊符号,可以完成许多奇怪的操作,比如下面这个:

所以可以给目录起名叫做"TEST=.",也可以指定环境变量PATH="TEST=.",所以如果指定polkit的PATH="TEST=.",并在目录"TEST=."下新建文件"test",同时将envp[0]设置为test的话:

通过这个技巧,我们达到了利用数组越界漏洞完成环境变量注入的目的操作。

要通过环境变量完成提权,最方便的就是劫持程序加载的libc,执行用户自己写的函数。

环境变量LD_PRELOAD就可以指定glibc的位置,使用户可以为某个二进制程序指定运行特定版本或者自己编译的libc,但是有SUID-bit的二进制程序在启动的时候不吃这个环境变量,那通过这个漏洞是不是可以将LD_PRELOAD注入polkit进程中进而劫持其glibc呢?很遗憾,在二进制程序正常运行的时候,glibc已经加载完成了,这时候指定LD_PRELOAD不会有任何作用。

所以要用到环境变量GCONV_PATH,该环境变量能够使glibc使用用户自定义的gconv-modules文件,而gconv-modules可以指定带有函数gconv()和gonv_init()的libc文件。在polkit源码中,多次使用了g_printerr函数进行报错,如果环境变量CHARSET不是UTF-8,g_printerr()将会调用函数iconv_open()来转换编码,此时iconv_open就会去根据环境变量GCONV_PATH寻找gconv-modules,并找到gconv-modules指定的libc文件,调用其中的gconv()与gonv_init()。

g_printerr()调用iconv_open()的路径为:

gconv-modules格式如下:

当程序中shell的环境变量为无效shell时就会触发g_printerr的报错:

所以利用步骤为:

创建目录'GCONV_PATH=.'

在目录'GCONV_PATH=.'下创建文件pwnkitdir

创建目录'pwnkitdir'

在目录下创建文件gconv-modules,写入内容"module UTF-8// PWNKIT// pwnkit 1"

编写c代码,编写名为gconv_init()的提权函数或者编写带有__attribute__ ((constructor))修饰的提权函数,编译为pwnkit.so,放在gconv-modules同级目录

编写c代码,用来运行pkexec,将argv设为{ NULL},a_envp设置为

并编译运行即可获得rootshell。

exp.c:

lib.c:

run.sh:

运行run.sh完成exp利用的前置环境搭建,切换为普通用户:

运行exp,完成提权。

......
for (n = 1; n < (guint) argc; n++)
    {
         ......
    }
    ......
  g_assert (argv[argc] == NULL);
  path = g_strdup (argv[n]);
    if (path == NULL)
    .....
    }
  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;
    }
......
for (n = 1; n < (guint) argc; n++)
    {
         ......
    }
    ......
  g_assert (argv[argc] == NULL);
  path = g_strdup (argv[n]);
    if (path == NULL)
    .....
    }
  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;
    }
g_printerr
    -> g_default_printerr_func
        -> print_string
         -> strdup_convert
            -> g_convert_with_fallback
                -> g_convert
                    -> open_converter
                        -> g_iconv_open
                            -> try_conversion
                                -> iconv_open
g_printerr
    -> g_default_printerr_func
        -> print_string
         -> strdup_convert
            -> g_convert_with_fallback
                -> g_convert
                    -> open_converter
                        -> g_iconv_open
                            -> try_conversion
                                -> iconv_open
module 字符集1// 字符集2// libc名字 cost
module 字符集1// 字符集2// libc名字 cost
char * envp[] = {
        "pwnkitdir",
        "PATH=GCONV_PATH=.",
        "CHARSET=PWNKIT",
        "SHELL=xxx",
        NULL
};

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (3)
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-8-17 09:20
1
雪    币: 15187
活跃值: (16852)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
3
感谢分享!
2023-8-18 09:28
0
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2023-8-18 09:35
0
游客
登录 | 注册 方可回帖
返回
//