CVE-2019-5736是由波兰CTF战队Dragon Sector在35C3 CTF赛后基于赛中一道沙盒逃逸题目获得的启发,对runc进行漏洞挖掘,成功发现的一个能够覆盖宿主机runc程序的容器逃逸漏洞。该漏洞于2019年2月11日通过邮件列表披露。
在讲这个漏洞之前,先简单说明一下什么是容器逃逸?
容器逃逸是指这样一种过程和结果:首先,攻击者通过劫持容器化业务逻辑,或直接控制(Caas等合法获得容器控制权的场景)等方式,已经获得了容器内某种权限下的命令执行能力;攻击者利用这种命令执行能力,借助一些手段进一步获得该容器所在直接宿主机(常见到“物理机运行虚拟机,虚拟机运行容器”的场景,该场景下的直接宿主机指容器外层的虚拟机)上某种权限下的命令执行能力。
基于以上说法,我的理解是:容器逃逸就是运行在容器内部的某些软件或者容器内部的某些用户获取到了容器外宿主机的命令执行权限。这种命令执行能力不包括宿主机文件或内存读写能力。(有理解不当的地方还请多指教)
话不多说,让我们开始复现漏洞。
CVE-2019-5736
漏洞原理:
Docker 18.09.2之前的版本使用的runc版本小于1.0.0-rc6,该runc版本存在漏洞,允许攻击者重写宿主机上的runc二进制文件,攻击者可以在宿主机上以root身份执行命令。
本次漏洞复现的环境:
Ubuntu18.04版本
docker 18.06.0-ce
runc 1.0.0-rc5+dev
kali(随便那个版本,用来充当服务器获取受害主机shell)
1、首先搭建环境:
如果出现以下报错可能是网络的问题,换一个网络即可(我当时用的是公司的网,所以报错,换成自己的网络就好了),然后重新执行以上命令即可。
以上命令执行完后会直接进入到docker环境中,要查看docker版本需要退出docker环境后查看。
以上脚本会自动拉取一个ubuntu镜像:
新打开一个终端,查看docker和runc的版本:
2、漏洞复现
下载poc文件:https://github.com/Frichetten/CVE-2019-5736-PoC
然后进入到CVE-2019-5736文件夹下面,修改main.go文件:注意要以管理员身份修改。
被抹掉的部分是服务器的ip
编译Poc文件中的main.go文件。注意:因为是.go文件所以实行这一步之前还需要下载golang-go和gccgo-go:
将编译好的main.go文件拷贝到运行的ubuntu容器中:
首先查看以下容器进程的id:
将go文件拷贝到容器中:
进入到docker环境中,查看docker里面的main文件:
在容器中安装golang-go和gccgo-go不然在容器中无法运行main文件:
首先要apt-get update否则无法下载golang-go和gccgo-go:
然后在docker的ubuntu容器环境中使用下面两条命令安装golang-go和gccgo-go:
apt install golang-go
apt install gccgo-go
下载好后运行main文件:
开启一台kali系统作为服务器,并开启监听模式:
开启一个新终端,模拟用户进入docker镜像:
触发漏洞后并没有打开交互式shell
返回到原来的终端能够看到回显:
返回到服务器端,已经获取到了反弹回来的运行docker容器的宿主机的shell:
ifconfig查看ip确认是否是受害主机的IP:
至此,漏洞复现完成。