BONAN RUAN / 安全研究

Kubernetes 后渗透研究

k0otkit

让编排机制,延续集群控制

k0otkit 是我在工业界工作期间开展的技术研究:在已有集群管理员权限之后,借助 Kubernetes 的原生资源,把单点访问扩展为持续的节点控制。

CIS 2020 · Kubernetes + rootkit · 原创机制示意

从管理员访问到节点持续控制的编排机制管理员访问用于修改 kube-proxy DaemonSet 模板,Secret 提供载荷。控制器把更新后的 Pod 分发到符合条件的节点;节点变化后继续调和期望状态。 期望状态 01 / ACCESS管理员访问已经取得的权限 02 / Secret编码载荷payload → env DaemonSet / kube-proxyPod 模板 控制器调和 NODE APod / kube-proxy原有容器新增容器NODE BPod / kube-proxy原有容器新增容器NODE CPod / kube-proxy原有容器新增容器符合条件的节点从管理员访问到节点持续控制的编排机制管理员访问用于修改 kube-proxy DaemonSet 模板,Secret 提供载荷。控制器把更新后的 Pod 分发到符合条件的节点;节点变化后继续调和期望状态。01 / ACCESS管理员访问02 / Secret编码载荷DaemonSet / kube-proxyPod 模板NODE ANODE BNODE C原有容器新增容器
一次模板变更,沿编排机制分发节点加入 / Pod 重建 → 同一模板
工业界技术研究绿盟科技 · 星云实验室
Post-penetration

管理员权限是起点

DaemonSet

节点分发与副本维持

CIS 2020

上海 · 技术研究演讲

取得管理员权限之后,
为什么还要借助编排

大型集群有许多节点。逐个访问、部署和维持连接会重复相同的工作;k0otkit 研究的是已有控制平面权限如何被原生机制放大。

01 / 权限前提

不是从零开始的入侵

原始场景先从控制节点上的容器逃逸,获得 root 与管理员 kubeconfig。k0otkit 接手的是后渗透阶段,使用已经具备的 API 权限。

02 / 节点覆盖

把重复任务交给控制器

DaemonSet 以模板表达节点工作负载。控制器为符合条件的节点维持 Pod,新节点加入或 Pod 被删除时继续按期望状态调和。

03 / 技术观察

从新增资源,走向已有模板

最初版本创建独立 DaemonSet,后续转为修改 kube-proxy 的 Pod 模板,并分离载荷、复用镜像、改用内存执行。可观测的变化也随之转移。

前提与机制:README、CIS 2020 slides 第 11–14 页,以及项目文章「基本思路」。节点覆盖取决于原有 DaemonSet 的调度条件。 README ↗

删掉一个 Pod,
模板还会让它回来

播放或点击步骤,观察最终设计从 API 资源走向节点进程。完成流程后,试试新增节点、删除 Pod,以及恢复原有模板。

K0OTKIT / 权限 → 模板 → 节点 → 进程浏览器机制示意 / 不连接集群
DaemonSet / kube-proxy原有 Pod 模板
containers: kube-proxy
Secret / payload尚未创建
依据调度条件分发
NODE A
Pod / kube-proxy
原有容器

管理员访问

NODE B
Pod / kube-proxy
原有容器

管理员访问

NODE C
Pod / kube-proxy
原有容器

管理员访问

等待运行时会话
原有容器模板中的新增容器

完成流程后,改变节点与期望状态

起点:已具备管理员访问;节点运行原有 Pod查看设计演进 ↘

这是依据最终设计制作的浏览器模型,节点数仅用于示意。实际更新受 DaemonSet 更新策略、准入与节点条件影响。删除 Pod 后会按当前模板重建;仅有容器进程退出时,通常由 kubelet 按重启策略重启容器。 k0otkit_template.sh ↗

每次迭代,改变一个暴露面

从独立 DaemonSet 到已有 Pod 模板,从载荷镜像到内存执行。切换版本,看资源、载荷、镜像和执行位置如何变化。

v1.0 / 技术演进

将载荷执行移到内存

动机
即使前面的部署通过管道完成,最终载荷文件仍是磁盘检测点。
变化
用 Perl 调用 memfd_create,将解码后的载荷写入内存文件并通过 /proc 文件描述符执行。目标侧无需创建 YAML 或载荷可执行文件。
边界
API 模板、Secret、进程与外联流量仍有可检测信号。该实现还要求已具备 admin 权限、兼容的 kube-proxy 镜像与 Linux 运行环境。

观察四个实现位置

API / 资源足迹

已有 kube-proxy 模板变更 + Secret

DATA / 载荷位置

Secret → 环境变量 → 内存文件

IMAGE / 镜像来源

已有 kube-proxy 镜像(需 Perl)

EXEC / 执行位置

memfd_create 内存文件执行

v0.1–v1.0 是 CIS 2020 slides 中的设计演进标签,对应文章中的基础实现与七次迭代;不表示仓库提供八个发布版本。这里比较实现机制与痕迹,没有性能或成功率数据。

控制能力的背面,是可观察的变化

2020 年的实现把多个已有特性串联起来。理解它的前提与痕迹,也就能理解演讲中防御思路的着力点。

API / 对象与权限

关注模板,而不只数 Pod

最终实现仍创建 Secret,并修改系统 DaemonSet 的容器和卷。资源数量看起来接近原状,也不能替代模板差异与管理员权限的检查。

模板与 Secret 源码 ↗

HOST / 镜像与隔离

已有镜像,也有运行前提

脚本依赖 kube-proxy DaemonSet、镜像中的 sh、echo、Perl,以及 Linux 载荷与系统调用约定。特权和宿主机挂载能否被接受,也会影响运行。

README 的运行条件 ↗

RUNTIME / 进程与流量

无磁盘载荷,仍有运行行为

内存执行减少目标侧载荷文件的痕迹,进程、内存文件与外联通信仍可观察。演讲讨论了资源审计、异常进程、系统调用与网络行为的检测。

内存执行源码 ↗

「无文件」针对目标侧 YAML 和载荷可执行文件;Secret 与 DaemonSet 仍是持久的 API 资源。攻击方准备脚本也会生成文件。本页按历史资料解释技术,不把当时的镜像和策略条件视为所有集群的共同配置。

从技术研究,
回到真实的工程与检测

k0otkit: A Universal Manipulation Technique in Post-Penetration against Kubernetes。CIS 2020 工业界演讲;技术文章于 2021 年 1 月发布。项目以 Kubernetes 的原生特性串联后渗透控制机制,并讨论对应检测思路。

Bonan Ruan · 绿盟科技 / 星云实验室 · 当时任安全研究员

资料范围与源码快照

源码核对于 2026-10-10,固定提交 1101f06162ebbcd382bcde9a5a364ed45476d4de。交互依据本地模板的最终设计;仓库另包含 2021 年补充的远程 API 变体。演进来自历史 slides 与文章,当前节点数量与动画均为机制示意。