当前位置:首页 > 焦点

docker remote api未授权访问漏洞

2018年,授权某安全团队做了一次全网扫描,访问结果让人后背发凉——超过7万台Docker引擎的漏洞2375端口直接暴露在公网上,没有任何认证。授权这意味着任何人只要能访问这个端口,访问就能在这台服务器上以root权限执行任意命令。漏洞不是授权提权,不是访问漏洞利用链,是漏洞直接执行。你打开浏览器输个URL,授权就能在别人服务器上创建容器、访问挂载宿主机根目录、漏洞读取所有文件。授权这件事过去好几年了,访问但今天扫一遍,漏洞仍然能捞到大量未授权实例。

问题的根源在于Docker默认配置的取舍。Docker Engine提供了一套RESTful API,用来管理镜像、容器、网络、卷。默认情况下它只监听Unix socket,也就是/var/run/docker.sock,本地通信,有文件权限兜底。但很多人为了图方便——比如想让远程CI/CD流水线控制Docker,或者用Portainer之类的工具管理多台主机——会把Docker配置成监听TCP端口。改法很简单,在/etc/docker/daemon.json里加一行"hosts": ["tcp://0.0.0.0:2375"],或者直接改systemd的启动参数。问题出在2375这个端口上:它是明文HTTP,且Docker本身不提供任何认证机制。2376端口对应的是TLS加密版本,但需要手动配置证书,很多人嫌麻烦就跳过了。

一旦2375端口对外开放且没有防火墙规则限制,攻击面就完全展开了。最直接的利用方式是通过API创建容器,把宿主机根目录挂载进去。一个典型的请求长这样:向/containers/create发POST,JSON body里指定"Binds": ["/:/host"],然后在容器里执行chroot /host,你就拿到了宿主机的完整shell。整个过程不需要任何 exploit,全是Docker提供的合法功能。另一种常见手法是创建privileged容器,挂载/dev,直接操作宿主机设备。再隐蔽一点的,往宿主机的/etc/cron.d/里写一个定时任务,或者覆盖/root/.ssh/authorized_keys。这些操作在API层面都是几行curl的事。

挖矿团伙对这类目标尤其敏感。2020年前后,大量暴露2375端口的服务器被扫到后,几分钟内就会被植入xmrig或者kinsing之类的挖矿木马。攻击者甚至不需要交互式shell,写个脚本批量调API创建挖矿容器就完事了。更麻烦的是,有些蠕虫会利用这个入口横向移动,扫描内网其他机器。你以为是台测试机无所谓,但它可能连着生产网段。

那怎么判断自己有没有中招?直接curl一下就行:curl http://your-ip:2375/version。如果返回了JSON格式的版本信息,说明API完全开放。再试curl http://your-ip:2375/containers/json,能看到容器列表的话,基本等于大门敞开。从外部扫描的角度,nmap -p 2375,2376配合--script docker-version就能快速识别。

修复这件事其实不复杂,但需要改架构思路。最稳妥的做法是别把Docker API暴露到TCP上,如果非要远程管理,走SSH隧道或者用socat做本地转发。确实需要TCP的,启用TLS双向认证,把2376端口配好,客户端证书、服务端证书、CA一个不能少。防火墙层面限制源IP,只允许跳板机或者CI节点访问。另外,Docker提供了--authorization-plugin机制,可以接入自定义的鉴权插件,不过配置成本偏高,小规模场景用TLS加网络ACL就够了。

有个细节容易被忽略:即使你只监听了127.0.0.1:2375,如果服务器上跑了其他Web应用存在SSRF漏洞,攻击者照样能通过本地回环访问Docker API。所以Unix socket的权限也得管好,别随便把/var/run/docker.sock挂进不受信任的容器里。这又是另一个话题了。

说到底,Docker remote API未授权访问不算传统意义上的“漏洞”——它更像是默认配置和用户便利性之间妥协的产物。Docker官方文档其实写得很清楚,2375不带加密和认证,只适合在受控网络里做调试。但现实是,大量教程、脚本、一键部署方案直接把它开在公网上,连个iptables规则都不加。扫一遍Shodan,这个数字至今没怎么降。

分享到: