虽然是个老洞了,但是前几天工作中又遇到了,所以拿出来研究回顾一下,并附上一些自己的理解。

0x00 安装

参考官方文档即可:官方文档
测试环境为Ubuntu 16.04 + Docker 17.03

0x01 配置Docker Remote API

修改/lib/systemd/system/docker.service文件中的dockerd启动参数,使其绑定在0.0.0.0上,导致未授权任意访问。

ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:8888

然后执行:

systemctl daemon-reload
systemctl restart docker.service

如果没有错误提示,则表示dockerd已经成功监听,可以通过如下命令进行验证:

curl "http://127.0.0.1:8888/v1.25/info"

这样的开启方法是非常危险的!请勿在生产环境中模仿!

0x02 攻击思路

通过docker client或者http直接请求就可以访问这个API,通过这个接口,我们可以新建container,删除已有container,甚至是获取宿主机的shell。
攻击方法很多,和Redis匿名访问的攻击思路大体一致,我这里列出来两点:

  1. 修改/root/.ssh/authorized_keys
  2. 修改/etc/crontab等计划任务文件

0x03 漏洞利用

  1. 获取images列表
    http://192.168.198.130:8888/v1.25/images/json
    可以获取到所有的images列表
    docker-images
    我们选取ubuntu:latest创建新的container。

  2. 创建新的container并挂载宿主机的/root/目录
    docker-images

  3. 运行并查看结果
    先把刚刚的container跑起来:
    POST http://192.168.198.130:8888/v1.25/containers/{container_id}/start
    其中container_id为刚刚创建时候返回的container id,注意是POST方法,不用传递任何数据。
    查看一下有没有错误
    GET http://192.168.198.130:8888/v1.25/containers/{container_id}/logs?stderr=True
    发现返回了错误信息:

/bin/sh: 1: cannot create /tmp/.ssh/authorized_keys: Directory nonexistent

我们按照步骤2的方式再重新打一次,将命令改为mkdir -p /tmp/.ssh,然后再重新echo一遍公钥。

  1. SSH连接
    可以看到宿主机的/root/.ssh目录下面确实出现了我们的公钥,SSH连接一下试试。

docker-images

直接登录

docker-images

通过这种方式其实有弊端,可能有些服务器被配置成不允许root用户登录,利用起来就会稍显繁琐,就不能这么轻松的拿到root shell了。

0x04 修复建议

可能有些人会认为,开在内网并无大碍,但实际上并非如此,一些类似SSRF之类的漏洞就可以轻易突破网络边界,再加上很多开发人员照搬文档教程,导致开放在2375默认端口,则为攻击者的内网探测减少了工作量。除了攻击者可以轻易获取root shell之外,内部的“内鬼”也可能对此漏洞加以利用,所以危害不容小觑。

那么如何修复这种漏洞呢,有几种方法:

  1. built in HTTPS encrypted socket
  2. 在docker api服务器前面加一个代理,例如nginx,设置401认证
  3. 设置iptables,只允许受信的机器访问该API接口