昨天我們透過操作 docker.sock ,建立一個掛入主機根目錄的新容器;即使沒有 Docker CLI,也能直接呼叫 API。那麼,如果容器裡連 docker.sock 都沒有,還有可能從容器存取主機檔案嗎?
今天換一個起點:容器內沒有 Docker CLI,也沒有掛載 docker.sock;但主機路徑已在容器啟動時掛入,這樣的掛載會如何影響主機安全?今天的主題是-Bind Mount。
從 Docker 官方文件可以了解到為什麼需要使用 bind-mounts:
參考來源:Bind mounts
官方文件列出了幾種適合使用 Bind Mount 的情境,例如:
因此,Bind Mount 最核心的功能可以理解成:讓 Container 直接存取 Host 上指定的檔案或目錄。
但就像刀子一樣,用得好生活便利,用不好就會傷到自己。有些使用者為了方便,索性直接把整個根目錄掛載到容器裡面。這時候就會出現一個尷尬的問題:

在 Day 12 我們提過:若未另外指定使用者,Docker 容器預設以 root 身分執行;主機根目錄下也有許多由 root 擁有的關鍵檔案。不過,容器內的 root 不代表一定有權修改主機檔案。當主機根目錄以可寫方式掛入容器,且容器內程序對目標檔案具有寫入權限時,就可能修改主機檔案。下面用一個簡單的實驗,看看這種掛載方式帶來的風險。
進入容器之後我們需要尋找根目錄有沒有被掛載,我們會先用 mount 查看容器目前掛載的目錄有哪些?
看到這些不用怕,我們把可疑的檔案路徑抓起來就好。整理好可疑的檔案路徑之後可以使用這個指令來查看 /host 對應的掛載資訊:
grep '檔案路徑' /proc/self/mountinfo

從這筆 mountinfo 紀錄可以看到,第四欄的 / 表示掛載的是該檔案系統的根目錄,第五欄的 /host 則是它在容器內的掛載位置。接著執行 chroot /host,讓新啟動的 shell 以 /host 作為 / 來查找檔案;下圖再將容器與主機的 /root 檔案清單進行比對:
上圖的左邊是容器環境而右邊是主機環境,左側是在容器內執行 chroot 後的 shell,右側是主機 shell;兩邊列出的 /root 檔案相互對應。
我們找到了裡面有一個 setup.sh 我們故意把腳本改寫成簡單的 Hello world。
echo 'echo "Hello world"' > /root/setup.sh

可以看到,主機上的 setup.sh 已被容器內的操作改寫,主機端以 bash setup.sh 執行時,會輸出 Hello world。
這證明在掛載與檔案權限均允許寫入的條件下,容器能修改主機檔案。結合 Day 08 與 Day 10 提到的執行流程,且主機後續以高權限執行這支遭改寫的腳本,攻擊者就可能進一步取得主機上的程式執行能力。因此,將主機根目錄以可寫方式掛載進容器,會帶來嚴重的安全風險。
今天的內容主要是補足 Day 14 為什麼會一直用到掛載根目錄的方式來當作提權的手法,其實 docker 的官方文件也有說明在做
bind-mounts 的時候必須非常小心,否則會造成危險的資安問題。
感謝大家的收看,明天我們將會接續討論特權容器的提權方式。
我們明天見!