本章涵盖内容包括:
? 交付云原生应用程序
? 确保使用Kubernetes部署的云原生应用程序的安全性
? 在基于容器化的环境中进行狩猎
? 从私有/公共云收集信息
? 在公共云Kubernetes基础设施中进行威胁狩猎探险
? 处理云原生数据集
随着云原生应用程序变得越来越普遍,你越来越可能需要在云中进行威胁狩猎。在本章中,我们将通过在托管云原生应用程序的公共云基础设施中进行一次探险来练习威胁狩猎。本章描述了Kubernetes,识别了Kubernetes基础设施中的关键数据源,并展示了如何收集和使用各种云基础设施事件进行威胁狩猎,突出了虚拟机和容器之间的差异。最后,本章记录了威胁狩猎游戏,并逐步介绍了威胁狩猎过程的步骤。
了解底层基础设施和数据源对于成功的威胁狩猎行动和探险至关重要。尽管我在本章中描述了参与这次威胁狩猎探险的云基础设施组件,但我鼓励您访问本章中的外部链接,以了解更多关于公共云基础设施和与Kubernetes相关概念的信息。
5.1 追踪被攻破的Kubernetes基础设施
第四章简要介绍了与容器化基础设施相关的基础概念。被攻破的基于云的应用程序(在Apache2上运行的WordPress)作为Kubernetes基础设施上的一个Pod在公共云提供商上运行。
我们在第四章中发现的安全事件引起了我们对容器和容器编排平台(如Kubernetes)更深入研究的兴趣。作为回应,我们决定进行一次威胁建模练习,以识别相关的威胁场景,然后设计并进行一次威胁狩猎,针对其中一个最相关的威胁场景:攻击者逃离Kubernetes容器并未经授权访问Kubernetes环境的大部分区域。图5.1显示了Kubernetes的核心构建块:集群、节点、Pod和容器。
定义 Kubernetes 集群由控制平面和一个或多个物理或虚拟机组成,这些机器被称为工作节点。工作节点托管着称为 Pod 的容器,每个 Pod 包含一个或多个容器。容器是一个可执行的镜像,它包括一个软件包及其所有依赖项。
容器是核心基础设施构建块,它们提供了用于交付现代应用程序的微服务架构。微服务架构旨在通过使用小型服务(每个服务运行在自己的进程中,例如容器)并通过使用轻量级机制(如API和Google远程过程调用(gRPC)进行通信)来实现大型私有和公共应用程序的快速、频繁和可靠的交付。
你应该熟悉从单体应用(图5.2)到基于微服务的架构(图5.3)的转变。你也应该熟悉实现这一转变的云基础设施,包括如何使用API来访问和管理应用程序和基础设施。
请注意,本章讨论的概念适用于其他托管的公共云基础设施,例如AWS弹性Kubernetes服务(EKS)、Azure Kubernetes服务(AKS)、阿里云Kubernetes容器服务(ACK)和IBM云Kubernetes容器服务(ACK)。这些概念也适用于使用标准Kubernetes的私有托管Kubernetes基础设施,以及如OpenStack和Rancher这样的编排平台。
5.1.1 威胁场景
基于我们在第四章进行的威胁狩猎考察,我们决定进行一次威胁建模练习,揭示与在公共云提供商上部署的Kubernetes集群相关的潜在威胁。威胁建模练习可以揭示与环境相关的威胁,突出这些威胁的影响级别。通过威胁建模练习识别出的威胁列表是相关威胁狩猎策略的良好来源。
基于我们在第四章进行的威胁狩猎考察,我们决定进行一次威胁建模练习,揭示与在公共云提供商上部署的Kubernetes集群相关的潜在威胁。威胁建模练习可以揭示与环境相关的威胁,突出这些威胁的影响级别。通过威胁建模练习识别出的威胁列表是相关威胁狩猎策略的良好来源。
来源—互联网
威胁—攻击者从Kubernetes容器中逃脱,并获得了对Kubernetes环境的大量未经授权的访问权限,包括托管节点和其他在Kubernetes集群中部署的其他Pod/容器。
然后,攻击者可以成功地与Kubernetes API服务器交互,收集集群信息并配置新的资源来运行恶意服务,例如加密货币挖矿、僵尸网络节点和Tor出口节点。
行为者—恶意个人、国家支持的团体或有组织犯罪行为者。
目标—托管在公共或私有云基础设施上的容器和Kubernetes节点。
攻击向量—攻击者获得对部署在Kubernetes上的特权容器的访问权限,或者拥有创建新的特权容器并访问主机资源的正确权限。
特权容器是一种部署时具有访问主机机器设备权限的容器,它摆脱了普通容器所受的限制。
威胁执行的影响—对手可能潜在地完全控制Kubernetes环境,包括所有节点和Pods。此外,对手可能能够托管绕过现有Kubernetes安全控制的隐蔽容器。
妥协指标(IOCs)—
– 从意外位置成功调用Kubernetes API服务器
– 使用意外账户成功调用Kubernetes API服务器
– 使用意外代理成功调用Kubernetes API服务器
– 集群中运行的未知Kubernetes pod
定义:逃离Kubernetes容器指的是利用容器作为跳板,移动到Kubernetes环境的其他部分,打破了容器化环境应该展现的基本隔离性。Kubernetes API服务器是托管在Kubernetes集群主节点上的关键控制平面组件,它提供基于REST API的操作服务。API服务器通过集群共享状态的前端为所有其他组件提供交互。监控对Kubernetes API服务器的调用对于安全检测和威胁狩猎至关重要。
5.1.2 研究工作
云原生应用程序托管在公共云服务提供商Google Cloud Platform (GCP)上。我们能够收集到一些关于云基础设施、应用程序和事件的初步信息,这些信息被收集并存储。
云
以下是运行在单个虚拟私有云(VPC)中的Google Kubernetes Engine (GKE)集群的详细信息:
? 公共云—GCP
? 区域—us-west1-a
? 平台—GKE
? 集群类型—GKE Standard(一种按节点计费的Kubernetes集群,您配置并管理集群节点)
? 集群大小—启用了集群自动伸缩,最小节点数为3,最大节点数为10。GKE集群的自动伸缩配置会根据工作负载需求自动调整节点数量。
? Kubernetes集群名称—production
? 部署Pods的命名空间—chapter5
? 运行API服务器的集群端点—35.199.171.183
? 集群Pod地址范围—10.48.0.0/14
? 服务地址范围—10.52.0.0/20
注意 VPC在公共云上创建了一个类似私有云的环境,通过托管网络服务、安全服务、虚拟机和Kubernetes集群等资源。如果需要,托管在VPC中的服务可以暴露给其他VPC或公共网络。
注意 在Kubernetes中,命名空间提供了一种在单个集群内隔离资源组的机制。集群有三个默认命名空间:kube-system(用于Kubernetes组件)、kube-public(用于公共资源)和default(用于用户资源)。可以根据需要创建新的命名空间。
列表5.1和5.2显示了使用kubectl(Kubernetes命令行工具,通过Kubernetes API与Kubernetes集群的控制平面通信)的集群详细信息。该工具允许授权的管理员远程与集群和Kubernetes对象进行交互和管理。
清单5.2显示了托管Kubernetes集群的三个节点的内部和外部IP地址。当你部署自己的Kubernetes集群时,你可能会收到一组不同的IP地址。
注意:托管在节点上的Pod在与该节点外部的Pod或系统通信时使用节点的IP地址。
应用程序
云原生应用程序的Web前端通过TCP/80和TCP/443端口暴露给互联网,使用云提供商的负载均衡服务。下面的列表显示了Kubernetes服务。
事件
根据研究,我们发现以下事件被收集并存储在Humio数据存储中:
对调用Kubernetes API服务器的通话进行审计日志记录,包括获取、列出、创建和删除请求。例如,使用kubectl进行的请求会被记录。
节点托管Kubernetes集群的OS日志,如列表5.2所示,由DaemonSet pod收集。节点运行的是基于Linux的操作系统版本。收集的事件包括系统配置更改、用户登录和安全外壳(SSH)会话。
公共Apache2 Web服务器的Web访问日志,托管Web前端应用程序。
云防火墙日志,记录进出节点的连接,这些节点为集群提供服务并托管Pod和服务。
注意:kubectl是一个命令行工具,允许您与Kubernetes API服务器交互,用于集群管理目的。例如,使用kubectl,您可以配置部署,获取Pod的状态,并检索Pod中容器的日志。您也可以使用其他工具(如curl)与Kubernetes API服务器交互。
定义:在Kubernetes中,DaemonSet是一个Pod特性,确保Pod被调度并在所有选定的集群节点上运行。这个特性对于部署后台功能(如事件收集)很有用。
为了更好地了解环境,我们要求云平台管理管理员提供Kubernetes部署的配置文件。这些文件使用YAML(另一种标记语言)编写,用于创建或更新Kubernetes组件,如Pod、部署、服务和角色。获取文件需要很长时间。我们应该在探险开始前等待它们的到来吗?我们应该期望在探险期间随时收到Kubernetes配置文件,所以让我们开始狩猎探险,不要等待它们的到来。
注意:等待这些文件的到来不应阻止您开始威胁狩猎探险。这些文件中的信息可能不会提供线索。
5.1.3 狩猎探险
我们将使用Kubernetes API服务器事件来搜索我们的第一个IOC:从意外位置对Kubernetes API服务器的成功调用。首先,让我们回顾一下Kubernetes API服务器事件的结构和内容。在本章中,我们不会在GitHub上有事件。事件和发现的详细信息在列表中提供。
Kubernetes API服务器事件
列表5.4是Kubernetes API服务器生成的示例事件。该事件对应于从授权于Kubernetes集群的远程主机执行命令kubectl get pods。该命令列出了Kubernetes集群上可用的Pod。
寻找第一个指标
意外位置意味着什么?为了回答这个问题,我们需要确定API调用的预期位置(“来源”),包括以下内容:
云平台管理员用于执行其常规系统管理任务的系统——在之前的API服务器事件中,193.188.105.36和111.65.33.215是已知的管理源IP地址。
用于管理、健康检查和收集指标的内部集群地址——在我们的案例中,以下已知的IP地址定期调用Kubernetes API服务器:10.138.0.168(托管Kubernetes调度器的IP地址)、127.0.0.1(IPv4环回IP地址)和::1(IPv6环回IP地址)。
托管Pods的节点的外部IP地址——在我们的案例中,它们是34.83.195.160、34.168.161.133和34.168.242.251。
云提供商系统用于收集关于Kubernetes集群指标的IP地址——在我们的案例中,以下是一些已知的属于GCP的源IP地址:108.177.73.0/24、108.177.67.0/24、66.249.93.0/24、74.125.209.0/24和66.249.84.0/24。
让我们运行一个搜索,查找来自上述列表之外的IP地址的API调用。这个搜索可能会帮助我们发现我们的第一批线索。在过去的24小时内,搜索我们的Humio数据存储产生的输出如列表5.5所示。
注意:您并不受我用来演示威胁狩猎探险步骤的数据存储平台的限制。您可以在其他平台上执行类似的搜索,例如Splunk和Elasticsearch。
搜索生成了以下事件列表,显示来自与不同用户代理(如callerSuppliedUserAgent和Mozilla/5.0 zgrab/0.x)关联的公共IP地址的请求。所有请求的决策字段值为forbid,这表明Kubernetes API服务器拒绝了传入的请求,这是应该的。
让我们执行相同的搜索,但只查找允许的API调用。
搜索没有返回任何事件。尽管没有从集群外部成功发起API调用,但这并不一定排除了从集群内部发起的未授权调用的可能性。让我们检查一下托管在集群上的Pods发起的成功调用。从集群中托管的Pods发起的调用到Kubernetes API服务器会离开集群,并可能使用节点的本地或公共IP地址。例如,从节点
gke-production-default-pool-3b82e871-momk离开的调用将分别使用10.138.0.26或34.83.195.160。
现在让我们搜索来自10.138.0.26或34.83.195.160的Kubernetes API调用,仔细关注与调用相关的用户代理和主体名称字段。主体名称字段包含用于进行API调用的账户。这次搜索涵盖了本章早些时候强调的第二个指标:使用意外账户成功调用Kubernetes API服务器。
搜索返回了许多具有不同主体名称和用户代理的事件,所有这些事件都使用了Kubernetes节点的公共IP地址之一,34.83.195.160。
输出显示了包含在principalEmail字段中的系统服务账户允许的API调用:
哪些服务账户应该有访问权限,哪些不应该?这个问题的答案并不是威胁猎人通常会知道的常识信息。云平台管理员可能会帮助我们回答这个问题。如果不行,我们可能需要联系公共云提供商(以我们的情况为例是谷歌)。否则,我们可以搜索Kubernetes文档(https://kubernetes.io)来寻找答案。
威胁猎人很好奇,所以让我们研究一下Kubernetes主体名称的话题,以了解哪些账户可以访问哪些信息。我们的研究显示所有的请求都是正常的,但是来自
system:serviceaccount:chapter5:default的请求可能不寻常,值得调查。chapter5是命名空间,而default是该命名空间中的默认服务账户。
注意:根据Kubernetes服务账户文档(https://mng.bz/QVX6),当你创建一个Pod时,如果你没有指定服务账户,它会自动分配给同一命名空间中的默认服务账户。
在Kubernetes中,这个默认服务账户默认没有与之关联的权限。
在默认服务账户的日志中发现活动使我们调查请求的资源和这些请求中进行的操作。让我们搜索所有与
system:serviceaccount:chapter5:default相关的API请求。
搜索返回以下输出,显示了许多允许的API调用和一些禁止的调用。
输出显示,在chapter5命名空间中的默认服务已经
? 使用某个版本的kubectl成功执行了操作
? 创建命名空间失败
警告:使用默认服务账户从容器向Kubernetes API服务器发出API调用是一个强烈的IOC(指示性操作特征)。
为了了解有关问题中默认账户当前可用的权限,我们要求云平台管理员针对托管应用程序的Kubernetes集群运行以下命令。该命令检索与账户
system:serviceaccount:chapter5:default相关的权限。
管理员提供了此命令的以下输出。
输出显示默认服务账户,
system:serviceaccount:chapter5:default,已被授予超出默认权限的权限。该账户可以对pod对象执行以下所有操作:获取、列出、监视、创建、删除、删除集合、修补和更新。服务账户还可以列出命名空间,但不能创建新的命名空间。
查找可疑API调用的来源
接下来想到的问题是这些API调用是从哪个容器发起的。请求可能由一个或多个容器发起。不幸的是,API服务器事件不包含哪些容器发起调用的信息。所有事件显示的调用者IP地址是Kubernetes节点的外部IP地址,34.83.195.160,作为调用者IP。这个IP地址用于从该节点上托管的容器向集群外部的IP地址发送流量,在这种情况下是Kubernetes API服务器。尽管Kubernetes API服务器事件无法帮助我们回答这个问题,但它们可以提供我们可以用来进一步调查的信息:用户代理,kubectl/v1.23.4 (linux/amd64) kubernetes/e6c093d。
注意 用户代理由调用者决定,并且可以被发起API调用的客户端更改。在发起请求时,攻击者可能会更改用户代理字符串,以反映像kubectl这样的常见用户代理。没有保证客户端是kubectl/v1.23.4。
在我们的狩猎行动中间,我们收到了我们从云平台管理员那里请求的Kubernetes基于YAML的配置文件,这是在开始狩猎行动之前。这些文件描述了一个名为production的集群中的部署。配置文件可能提供一些重要信息,这将帮助我们揭示有价值的线索,所以让我们立即处理它们包含的信息。
注意:在进行探险时,预计会受到中断。威胁猎人会在进行探险时接收到信息或被要求提供信息。账户可以获取、列出、观看、创建、删除、删除集合、修补和更新pod。账户可以获取、列出和监视命名空间。猎人需要优先处理并选择首先处理什么。根据探险的状态和紧急性,你可能希望在处理传入请求之前继续你的探险。
特别引起我们注意的是特定的门户部署配置文件,即portal.yaml。如列表5.14所示,门户部署的规范允许容器以特权模式运行。privileged设置为true。这种配置允许容器几乎无限制地访问宿主机。这种配置本身并不代表威胁执行,但如果对手能够破坏运行在容器上的应用程序并获得shell访问权限,这将是一种可能导致严重系统漏洞的配置错误。
默认情况下,容器以非特权模式运行。这种默认模式允许它们使用底层系统资源,同时通过容器运行时与宿主机系统和其他在同一系统上运行的容器隔离开来。容器可以使用分配的计算、内存和磁盘资源,而无法读取节点上的文件或其他容器的文件。
警告:在特权模式下运行容器是危险的。攻击者如果获得了部署在Kubernetes上的特权容器的访问权限,或者拥有创建新特权容器的适当权限,他们可以访问宿主机的资源。
令人担忧的观察数量正在增加:
? 一个或多个Pod上的默认账户正在成功地向Kubernetes API服务器发起调用。
? Web前端部署在具有特权模式的Pods上。
我们立即要求云平台管理员在门户部署中的所有Pod上运行几个命令,以寻找潜在的妥协。搜索将在运行在chapter5命名空间中的容器中执行,寻找使用默认服务账户在API请求中使用的kubectl客户端的容器。
提示 为了加快狩猎工作,你可能希望与平台管理员进行交互式会话,无论是物理上的还是虚拟的,而不是发送请求并等待响应。
输出显示,在/tmp目录中存在一个名为kubectl的文件。经过检查,平台管理员确认kubectl不是原始容器镜像的一部分。这引发了几个问题:
? 文件kubectl是如何到达那个容器的?
? 是否从那个容器中执行了kubectl,如果是,使用了什么命令来执行它?
回顾我们可用的数据源,我们有节点操作系统审计日志,这些日志由集群上部署的一个事件收集DaemonSet收集。下面的列表显示了用于收集节点审计日志的DaemonSet类型的pod。
在研究了节点审计日志的内容后,我们得出结论,它们不包括在容器中本地执行的命令。这并不是要贬低收集节点审计日志的重要性,这些日志在本次探险或未来的探险中可能会派上用场。
记录容器中执行的命令
为了能够查看在容器中执行的命令,我们可以转向扩展伯克利数据包过滤器(eBPF;https://ebpf.io),这是一个基于Linux内核的构造,它允许扩展内核功能,而无需重新编译内核或加载新的内核模块。托管Kubernetes集群的节点运行Linux。部署后,eBPF可以让我们看到集群内执行的命令,这有助于我们确定发生了什么,发生在何处,以及谁发起了它。
注意 使用eBPF,你可以记录和日志化在kubectl exec会话中执行的命令,你可以将这些事件转发到数据存储。然后你可以回放会话并查看确切的事件序列。
不幸的是,在与云管理员核实后,我们发现eBPF尚未部署在集群中——至少目前还没有。为了开始捕获容器上执行的命令,我们要求平台管理员部署Falco(https://falco.org),这是一个开源的运行时监控安全工具,用于容器化部署,它使用eBPF作为底层结构。Falco允许我们捕获并报告容器中的意外执行。在解释了情况之后,平台管理员接受了请求,并在chapter5命名空间上部署了Falco。
警告 尽管猎人可以请求部署新的事件收集和安全检测工具,但在生产系统中部署这些工具之前,应该进行彻底的评估和测试。
以下列表显示了作为DaemonSet运行的pods:cos-auditd-logging-h8f2l正在收集节点审计日志,而falco-5j8zw正在运行Falco。
Falco 基于规则集监控系统行为,并在运行时检测到威胁时发出警报。我们通过使用在 https://mng.bz/6Ype 上发布的默认规则集来部署 Falco。默认规则集包含以下两条用 YAML 编写的规则。这些规则监控容器中的客户端执行情况,并尝试从容器中联系 K8S API 服务器。
部署Falco几小时后,我们收到了以下安全事件。
第一个事件是一个警告消息,显示从 pod portal-5647ffc5d7-bd9pv 发出的 kubectl 命令用于在 chapter5 命名空间上使用 miningcontainers/xmrig 镜像创建一个新的部署。miningcontainers/xmrig 是一个用于加密货币挖矿的容器镜像(详情见
https://github.com/mining-containers/xmrig)。用于连接 API 服务器的令牌被屏蔽,--token=***,但我们能看到连接中使用的证书颁发机构证书指向
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt。
第二个事件与第一个事件相关,但提供了连接的源 IP 地址,10.48.3.16,这是 pod 的 IP 地址。第三个事件显示了一个使用 wget 向 http://84.32.188.69:9999 请求文件的事件,父进程是 xmrig.sh。
现在我们有证据表明有人或某物正在使用存储在
/var/run/secrets/kubernetes.io/serviceaccount/ 的凭据从 pod portal-5647ffc5d7-bd9pv 执行 kubectl,这是服务账户凭据和其他信息在容器中默认存储的位置。10.48.3.16 是我们之前看到的以特权模式运行的 web 门户 pod 的 IP 地址。
/var/run/secrets/kubernetes.io/serviceaccount 是一个挂载目录,它默认包含以下文件。
我们之前已经确定, 默认的服务账户没有默认关联的权限。我们需要找出是谁更改了这个账户的权限,为什么更改,以及何时更改的。
找出谁更改了服务账户权限
在列表5.24中,我们搜索包含Kubernetes RoleBinding请求的API事件,以找出是谁更改了默认服务账户的权限。角色绑定授予特定命名空间内用户或账户的权限。我们尝试搜索过去几个月的事件,以发现与狩猎行动相关的RoleBinding更改。
以下列表中的搜索结果显示,kubectl命令是由前管理员在协调世界时(UTC)6月26日19:58发出的。
更改默认服务账户权限应被禁止。为什么管理员会在一天结束时做出这样的更改?这是否可能是内部人士驱动或协助的妥协,出于某种未知的动机(财务、个人等)?或者这是否是前管理员的系统被妥协,然后被用来更改默认服务账户的情况?为了回答这些问题,让我们分析从以下事件收集的时间线:
- 前管理员在chapter5命名空间中对默认服务账户所做的更改
- 从使用默认服务账户的Pod发出的kubectl命令
时间线揭示了看似可交付的更改和测试事件序列。对默认服务账户进行更改后,从Pod发出kubectl命令。这并不一定指控前管理员。攻击者可能同时获得了对Pod和管理员系统的未授权访问。
由于怀疑有内部人员的参与(前管理员),我们应该联系人力资源和法律团队。事件响应经理通常是联系点,并将向这些团队简报发现的情况并咨询未来的行动或预防措施。法律团队会就处理证据、团队间沟通和共享事件信息提供建议。
注意:管理事件的法律方面超出了本书的范围。猎人们应该标记可能需要法律建议的事项,以供其他事件响应团队和事件经理(如果存在的话)参考。
关于加密货币挖矿事件的更多信息
回到我们之前发现的加密货币挖矿部署事件,让我们检索所有命名空间中部署的Pod列表。
我们注意到那些以web-front开头的pods。这些pods对应于列表5.20、5.21和5.22中的Falco事件。这些输出表明了一次加密货币挖矿操作——未经授权使用计算能力来挖掘加密货币。
根据我们收集的所有信息,我们已经证实了这个假设:一个攻击者逃离了Kubernetes容器,并且未经授权访问了Kubernetes环境的大部分区域。现在是时候将案件移交给事件响应团队了,他们将继续调查以遏制威胁,并与不同的团队(云平台管理、应用程序所有者、人力资源和法律团队)协调。威胁猎人仍然参与支持调查,并分享可以预防、检测和应对未来类似威胁的建议。