23 lines
2.9 KiB
Markdown
23 lines
2.9 KiB
Markdown
### runc 容器逃逸原理
|
||
|
||
**1. 竞争条件**
|
||
|
||
这是 runc 容器逃逸中一种经典的利用方式。以 **CVE-2019-5736** 为例,其核心原理是:
|
||
|
||
- **进程切换和文件句柄劫持**:当我们在宿主机上执行 `docker exec` 等命令时,实际上 runc 会在容器内启动一个新的进程。在 runc 启动这个新进程到真正执行用户指定命令的这段极短的时间内,存在一个“窗口期”
|
||
- **恶意代码的快速覆盖**:攻击者可以在容器内通过一个精心设计的恶意程序,持续地监控并尝试以写权限打开 runc 进程的文件句柄(`/proc/self/exe`)。一旦 runc 进程完成了权限降级,文件句柄被释放但尚未关闭,攻击者的恶意程序就会立即抢占这个句柄,并向宿主机上的 runc 二进制文件写入恶意 payload
|
||
- **获得宿主机 root 权限**:当 runc 尝试执行后续命令时,它执行的不再是正常的二进制文件,而是已经被篡改的恶意代码。因为 runc 本身是以 root 权限在宿主机上运行的,所以攻击者就成功地以 root 权限执行了任意命令,实现了容器逃逸
|
||
|
||
**2. 特权模式与危险配置**
|
||
|
||
虽然这不是 runc 自身的漏洞,但它是最常见的容器逃逸方式之一,常常与 runc 的使用有关
|
||
|
||
- **特权容器(Privileged Container)**:如果一个容器被以特权模式启动(`docker run --privileged`),它将获得几乎所有宿主机的 root 能力。这种模式下,容器内的进程可以访问宿主机上的所有设备、挂载宿主机的文件系统,甚至可以操纵内核模块。攻击者可以轻易地通过挂载宿主机根目录并使用 `chroot` 命令切换根目录,从而完全控制宿主机
|
||
- **Docker Socket 挂载**:另一种常见配置错误是直接将 `/var/run/docker.sock`(Docker 守护进程的 Unix Socket)挂载到容器内部。这样做的后果是,容器内的进程可以直接与 Docker 守护进程通信,相当于拥有了在宿主机上创建、运行、停止任何容器的权限。攻击者可以利用这个权限创建另一个特权容器,将宿主机根目录挂载进去,然后轻松实现逃逸
|
||
|
||
**3. 文件描述符泄漏与符号链接**
|
||
|
||
最近的漏洞,如 **CVE-2024-21626**,则利用了另一种机制:
|
||
|
||
- **工作目录和文件描述符**:这个漏洞是由于 runc 在处理容器进程的启动和工作目录时存在缺陷。攻击者可以利用 `/proc/self/fd/` 这个特殊目录,通过设置容器的工作目录或创建符号链接,来访问本不应该被容器访问到的宿主机文件描述符
|
||
- **突破命名空间隔离**:容器通过命名空间(Namespaces)机制来隔离文件系统、进程、网络等资源。但是,如果攻击者可以找到一种方式,让容器内的进程能够操作宿主机上的文件句柄,那么就可以绕过这些命名空间的隔离,从而读写宿主机上的任意文件,最终实现逃逸 |