容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

admin 2024年2月21日00:20:00评论12 views字数 6267阅读20分53秒阅读模式

最近在搞CTF的出题,就看到了《红蓝对抗中的云原生漏洞挖掘及利用实录》中关于Serverless 实战能挖到的漏洞的总结,这里就复制粘贴出来,作为记录。也说一下自己2023年在阿里SRC 挖了很多云原生/serverless相关漏洞,参考下面的漏洞总结,照着挖就行,搞个10W不成问题。 

作者重点介绍了十个漏洞中的CVE-2020-15257,该漏洞在实际攻防场景中起到了重要作用。此外,作者还提到了容器、容器编排组件API配置不当或未鉴权的问题,这是业界普遍接触最多、最首当其冲的安全问题之一。最后,作者列举了一些常见开放服务指纹,供读者参考。

容器相关组件的历史漏洞

2020年我们和腾讯云的同学一起处理跟进分析了多个官方开源分支所披露的安全问题,并在公司内外的云原生能力上进行复现、分析,从产品和安全两个角度出发探讨攻击场景,保障云用户和业务的安全。

其中投入时间比较多的,主要是以下十个漏洞,每个都非常有趣,且都在云产品上得到了妥善的跟进和安全能力建设:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

实际攻防场景里面我真实用过且在关键路径里起到作用的也就 CVE-2020-15257,其它漏洞的POC都只在漏洞公开时自建测试的环境复现和公司内服务的漏洞挖掘用了一下,有些环境虽然有漏洞,但是实际打真实目标却没怎么用得上。

值得一提的是最开始跟进分析时,因为EXP需要钓鱼让管理员去执行 docker exec 或 kubectl exec 才可以触发,所以不怎么看好的 CVE-2019-5736 RUNC 容器逃逸漏洞;反而是真的遇到几个无交互即可触发的场景。主要是 vscode server、jupyter notebook、container webconsole 等这种提供容器内交互式shell的多租户场景在企业内网里变多了,容器逃逸之后就是新的网络环境和主机环境。

就安全问题来说,业界普遍接触最多、最首当其冲的就是容器组件服务的未鉴权问题。我们在2019年的时候整理了一份Kubernetes架构下常见的开放服务指纹,提供给到了地表最强的扫描器洞犀团队,就现在看来这份指纹也是比较全的。

  1. kube-apiserver: 6443, 8080

  2. kubectl proxy: 8080, 8081

  3. kubelet: 10250, 10255, 4149

  4. dashboard: 30000

  5. docker api: 2375

  6. etcd: 2379, 2380

  7. kube-controller-manager: 10252

  8. kube-proxy: 10256, 31442

  9. kube-scheduler: 10251

  10. weave: 6781, 6782, 6783

  11. kubeflow-dashboard: 8080

前六个服务的非只读接口我们都曾经在渗透测试里遇到并利用过,都是一旦被控制可以直接获取相应容器、相应节点、集群权限的服务,也是广大公网蠕虫的必争之地。

组件分工

各个组件未鉴权所能造成的风险,其实从它们在Kubernetes集群环境里所能起到的作用就能很明显的判断出来,如 APIServer 是所有功能的主入口,则控制 APIServer 基本上等同控制集群的所有功能;而 kubelet 是单个节点用于进行容器编排的 Agent,所以控制 kubelet 主要是对单个节点下的容器资源进行控制。

组件分工上较为完整的图例可参考:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

想必这样也相对晦涩难懂,我简化了一下,假如用户想在集群里面新建一个容器集合单元,那各个组件以此会相继做什么事情呢?

  1. 用户与 kubectl 或者 Kubernetes Dashboard 进行交互,提交需求。(例: kubectl create -f pod.yaml);

  2. kubectl 会读取 ~/.kube/config 配置,并与 apiserver 进行交互,协议:http/https;

  3. apiserver 会协同 ETCD 等组件准备下发新建容器的配置给到节点,协议:http/https(除 ETCD 外还有例如 kube-controller-manager, scheduler等组件用于规划容器资源和容器编排方向,此处简化省略);

  4. apiserver 与 kubelet 进行交互,告知其容器创建的需求,协议:http/https;

  5. kubelet 与Docker等容器引擎进行交互,创建容器,协议:http/unix socket.

至此我们的容器已然在集群节点上创建成功,创建的流程涉及ETCD、apiserver、kubelet、dashboard、docker remote api等组件,可见每个组件被控制会造成的风险和危害,以及相应的利用方向;对于这些组件的安全性,除了不同组件不一样的鉴权设计以外,网络隔离也是非常必要的,常规的 iptables 设置和规划也可以在容器网络中起到作用(容器网络的很多能力也是基于 iptables 实现的),另外比较有容器特色的方案就是 Network Policy 的规划和服务网格的使用,能从容器、POD、服务的维度更加优雅的管理和治理容器网络以及集群内流量。这些组件的资料和对应渗透手法,这里我们一一介绍一下:

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 都是有鉴权的:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

当然也有未鉴权的配置:kube-apiserver —insecure-bind-address=0.0.0.0 —insecure-port=8080,此时请求接口的结果如下:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

对于这类的未鉴权的设置来说,访问到 apiserver 一般情况下就获取了集群的权限:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

可能还有同学不知道 apiserver 在 Kubernetes/容器编排集群里的重要地位,这里简单介绍一下:在蓝军眼中的 Kubernetes APIServer其重要性,如下图:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

所以,对于针对Kubernetes集群的攻击来说,获取 admin kubeconfig 和 apiserver 所在的 master node 权限基本上就是获取主机权限路程的终点。
至于如何通过 apiserver 进行持续渗透和控制,参考 kubectl 的官方文档是最好的:
https://Kubernetes.io/docs/reference/generated/kubectl/kubectl-commands

kubelet

每一个Node节点都有一个kubelet服务,kubelet监听了10250,10248,10255等端口。

其中10250端口是kubelet与apiserver进行通信的主要端口,通过该端口kubelet可以知道自己当前应该处理的任务,该端口在最新版Kubernetes是有鉴权的,但在开启了接受匿名请求的情况下,不带鉴权信息的请求也可以使用10250提供的能力;因为Kubernetes流行早期,很多挖矿木马基于该端口进行传播和利用,所以该组件在安全领域部分群体内部的知名度反而会高于 APIServer。

在新版本Kubernetes中当使用以下配置打开匿名访问时便可能存在kubelet未授权访问漏洞:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

如果10250端口存在未授权访问漏洞,那么我们可以先使用/pods接口获取集群的详细信息,如namespace,pods,containers等

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

之后再通过
curl -k https://Kubernetes-node-ip:10250/run/// -d “cmd=id” 的方式在任意容器里执行命令

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

此时,选择我们所有控制的容器快速过滤出高权限可逃逸的容器就很重要,在上述 /pods API 中可以获取到每个 POD 的配置,包括了 host*、securityContext、volumes 等配置,可以根据容器逃逸知识快速过滤出相应的POD进行控制。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

由于这里10250鉴权当前的Kubernetes设计是默认安全的,所以10255的开放就可能更加容易在红蓝对抗中起到至关重要的作用。10255 本身为只读端口,虽然开放之后默认不存在鉴权能力,无法直接利用在容器中执行命令,但是可以获取环境变量ENV、主进程CMDLINE等信息,里面包含密码和秘钥等敏感信息的概率是很高的,可以快速帮我们在对抗中打开局面。

dashboard

dashboard是Kubernetes官方推出的控制Kubernetes的图形化界面,在Kubernetes配置不当导致dashboard未授权访问漏洞的情况下,通过dashboard我们可以控制整个集群。

在dashboard中默认是存在鉴权机制的,用户可以通过kubeconfig或者Token两种方式登录,当用户开启了enable-skip-login时可以在登录界面点击Skip跳过登录进入dashboard

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

然而通过点击Skip进入dashboard默认是没有操作集群的权限的,因为Kubernetes使用RBAC(Role-based access control)机制进行身份认证和权限管理,不同的serviceaccount拥有不同的集群权限。我们点击Skip进入dashboard实际上使用的是Kubernetes-dashboard这个ServiceAccount,如果此时该ServiceAccount没有配置特殊的权限,是默认没有办法达到控制集群任意功能的程度的。

但有些开发者为了方便或者在测试环境中会为Kubernetes-dashboard绑定cluster-admin这个ClusterRole(cluster-admin拥有管理集群的最高权限)。

这个极具安全风险的设置,具体如下:

1、新建dashboard-admin.yaml内容如下(该配置也类似于“利用大权限的 Service Account”一小节的配置 )

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

2、执行kubectl create -f dashboard-admin.yaml
此时用户通过点击Skip进入dashboard即可拥有管理集群的权限了。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

进入到dashboard我们可以管理Pods、CronJobs等,这里介绍下我们如何通过创建Pod控制node节点。

我们新建一个以下配置的Pod,该pod主要是将宿主机根目录挂载到容器tmp目录下。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

之后我们便可以通过该容器的tmp目录管理node节点的文件。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

值得注意的是,为了集群的稳定性和安全性要求,在Kubernetes默认设计的情况下Pod是不能调度到master节点的,但如果用户自行设置关闭了Master Only状态,那么我们可以直接在master节点新建Pod更直接的控制master node;不过目前各大主流云产商上的Kubernetes集群服务,都会默认推荐让Master节点由云厂商托管,更加加剧了Master节点渗透和控制的难度 。

etcd

etcd被广泛用于存储分布式系统或机器集群数据,其默认监听了2379等端口,如果2379端口暴露到公网,可能造成敏感信息泄露,本文我们主要讨论Kubernetes由于配置错误导致etcd未授权访问的情况。Kubernetes默认使用了etcd v3来存储数据,如果我们能够控制Kubernetes etcd服务,也就拥有了整个集群的控制权。

在Kubernetes中用户可以通过配置/etc/Kubernetes/manifests/etcd.yaml更改etcd pod相关的配置,倘若管理员通过修改配置将etcd监听的host修改为0.0.0.0,则通过ectd获取Kubernetes的认证鉴权token用于控制集群就是自然而然的思路了,方式如下:

首先读取用于访问apiserver的token

export ETCDCTL_API=3
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key
etcdctl get / —prefix —keys-only | grep /secrets/kube-system/clusterrole
etcdctl get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-jmrzx

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

利用token我们可以通过apiserver端口6443控制集群

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

docker remote api

Docker Engine API是Docker提供的基于HTTP协议的用于Docker客户端与Docker守护进程交互的API,Docker daemon接收来自Docker Engine API的请求并处理,Docker daemon默认监听2375端口且未鉴权,我们可以利用API来完成Docker客户端能做的所有事情。

Docker daemon支持三种不同类型的socket: unix, tcp, fd。默认情况下,Docker daemon监听在unix:///var/run/docker.sock,开发者可以通过多种方式打开tcp socket,比如修改Docker配置文件如/usr/lib/systemd/system/docker.service:

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

之后依次执行systemctl daemon-reload、systemctl restart docker便可以使用docker -H tcp://[HOST]:2375这种方式控制目标docker

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

因此当你有访问到目标Docker API 的网络能力或主机能力的时候,你就拥有了控制当前服务器的能力。我们可以利用Docker API在远程主机上创建一个特权容器,并且挂载主机根目录到容器,对主机进行进一步的渗透,更多利用方法参考容器逃逸章节。

检测目标是否存在docker api未授权访问漏洞的方式也很简单,访问http://[host]:[port]/info路径是否含有ContainersRunning、DockerRootDir等关键字。

kubectl proxy

kubectl proxy这个子命令大家可能遇到比较少,这里单独介绍一下;由于上述几个组件的安全问题较为常见和出名,且在目前开源分支里它们在鉴权这个方面都是默认安全的,所以直接出现问题的可能性较小,企业在内外网也都收敛得不错;此时 kubectl proxy 这个子命令反而是另一个常见且蠕虫利用起来非常简单粗暴的问题。

了解使用过Kubernetes的同学应该知道,如果你在集群的POD上开放一个端口并用ClusterIP Service绑定创建一个内部服务,如果没有开放NodePort或LoadBalancer等Service的话,你是无法在集群外网访问这个服务的(除非修改了CNI插件等)。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

如果想临时在本地和外网调试的话,kubectl proxy 似乎是个不错的选择。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

但其实 kubectl proxy 转发的是 apiserver 所有的能力,而且是默认不鉴权的,所以 —address=0.0.0.0 就是极其危险的了。

容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

所以这里的利用和危害和 APIServer 的小节是相似的。

原文始发于微信公众号(黑伞安全):容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月21日00:20:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   容器、容器编排组件 API 配置不当或未鉴权-SRC真的能遇到http://cn-sec.com/archives/2509244.html

发表评论

匿名网友 填写信息