ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

云原生安全实战:从容器逃逸到K8s集群漏洞挖掘

云原生安全实战:从容器逃逸到K8s集群漏洞挖掘 云原生火了这么多年容器和K8s几乎成了企业后端的事实标准。但和所有新技术一样它带来便利的同时也把攻击面从单台机器拉到了一个跨主机、跨网络的分布式平面上。我自己在做企业安全评估和漏洞挖掘的时候感受最深的一点是传统的端口扫描、Web漏洞检测那一套在云原生环境里往往行不通甚至会被容器网络和负载均衡直接过滤掉。真正的高危漏洞藏在镜像、编排配置、权限模型和运行时隔离这些更核心的层次里。这篇内容我打算用一次企业级云原生漏洞挖掘项目的视角来聊聊容器和K8s安全的攻击面分布在哪里、怎么从镜像到运行时一层层找问题、K8s控制面有哪些常见的致命配置以及最后整理一些我在实际挖掘和排查中踩过的坑。不管你是刚接触云原生安全的新手还是已经在做SRC漏洞挖掘想往企业级场景深挖这篇文章应该都能给你一些可以直接上手的思路。1. 云原生安全的本质容器和K8s到底在防什么先说一个特别容易被误解的事情很多人觉得容器安全等于镜像安全把镜像扫描一遍没漏洞就觉得高枕无忧。但云原生环境真正难防的地方在于它的信任边界是动态的。传统虚拟机时代一台物理机一个虚拟机边界是Hypervisor隔离出来的很清晰。容器不一样同一个节点上几十个容器共享一个内核边界是内核的各种命名空间和cgroup机制画出来的天然就更薄。一旦有一个容器被攻破攻击者离宿主机可能只差一个系统调用。1.1 云原生架构引入的新攻击面咱们把云原生架构拆开看攻击面大概分成四层镜像层基础镜像里带的历史漏洞、错误打包进镜像的密钥和配置文件、供应链投毒、镜像仓库本身未授权访问。运行时层容器逃逸漏洞、不安全的capabilities配置、特权容器、已挂载的敏感目录比如宿主机的rootfs、docker.sock。编排层K8s的API Server暴露、RBAC权限配置错误、etcd未加密或未认证、kubelet匿名访问、Pod安全策略缺失。网络层东西向流量完全开放、服务间无加密、负载均衡暴露了内部服务、SSRF漏洞配合云元数据接口打到云凭证。这四层不是独立的攻击者往往是从Web漏洞比如某个Java应用的反序列化进到Pod拿到一个WebShell然后开始横向在集群内找更高权限的东西。所以云原生漏洞挖掘本质上是把这四层都当成一个连续的攻击链来看而不是单点检测。1.2 容器安全与K8s安全的分工再理清一下概念。我在跟很多做安全测试的朋友聊的时候发现大家经常把容器安全和K8s安全混在一起其实它们的防护对象和检测手段有明显区别维度容器安全K8s安全防护对象单容器、镜像、运行时集群、控制面、工作负载调度核心风险逃逸、提权、镜像漏洞未授权API、越权、敏感数据泄露典型测试手段镜像扫描、capability检查、容器内探测权限枚举、审计日志分析、网络策略验证典型工具Trivy、Grype、Docker Benchkube-hunter、kubeaudit、kube-bench打个比方容器安全像是给每个房间单独检查门窗和贵重物品K8s安全则是检查整栋楼的物业管理、门禁卡权限体系和楼层之间有没有防火隔离。两者都得测但思路完全不是一个量级。很多企业恰恰是只给房间装了摄像头镜像扫描却忘了楼道的大门和电梯卡是随便刷的。1.3 企业环境的真实痛点企业级环境和测试环境的最大区别在于“历史包袱”和“混合部署”。我不止一次遇到这种情况生产环境里既有裸金属上的虚拟机又有自建的K8s集群还有十几个不同业务线自己建的namespace权限模型五花八门。有的集群是两年前部署的那时PodSecurityPolicy还在用Admission Controller方式硬塞进去的后来K8s升级之后策略直接失效了。还有的集群为了图省事把kubelet的匿名访问开着相当于任何能触达节点的网络请求都能拿到节点上所有Pod的状态信息。这些历史配置就像放了很久的外墙——验房报告上说墙没问题但实际一戳就能捅破。所以做企业级云原生安全测试一定不能只看“当前配置漂不漂”还得看“历史上有没有改过、有没有被绕过”。这个排查底子和配置变更审计比扫一百个CVE都重要。2. 容器漏洞挖掘从镜像到运行时的完整链路容器这块的挖掘我习惯从下往上走先看镜像有什么问题再看运行时配置和隔离现状最后才是容器内的权限和挂载。先给大家一个基础但好用的思路镜像漏洞不等于可利用漏洞。Trivy扫出一个CVSS 9.8的高危漏洞不代表攻击者真的能打进来——可能对应的组件根本没被调用可能漏洞利用需要特定的场景。所以别一看到高危漏洞就慌要把可利用性放到业务上下文中去判断。2.1 镜像层的挖掘思路镜像扫描是入门第一件事但很多人只用了扫描工具会的那部分。我实际测下来镜像层的挖掘重点其实有三个第一是历史层和缓存层里的残留文件。很多镜像不是从零写的Dockerfile里经常有apt-get update然后又删掉某些deb包的操作但Deleted层的文件并没有真正消失只是在层叠加中被标记为删除。如果攻击者拿到了镜像tar包完全可以重新打开这些旧层找到被“删除”的密钥、源码、内网地址。我以前做测试时真的在一个公共镜像的旧层里翻到过一个云服务商的AK/SK那个字段是某位开发在调试时随手写进环境变量、后来又删掉换掉了但旧层还在。第二是基础镜像版本过旧。这一点在企业里特别普遍因为运维往往抱持“能跑就不动”的心态。比如很多Java应用还跪在OpenJDK 8的老版本上对应的一些反序列化漏洞补丁根本没打进去。这类漏洞能不能打要看应用本身用了什么组件所以我建议配合docker history和docker inspect看一下镜像构建的上下文而不是只看扫描报告。第三是未授权访问的镜像仓库。这个比前面两个更“香”。如果镜像仓库比如Harbor、Docker Registry没有加访问控制或者配置了匿名拉取攻击者就能直接把所有业务镜像拖下来离线慢慢翻。镜像里的环境变量、配置中心地址、数据库连接串都是敏感信息的高发地。更隐蔽的情况是仓库开放push权限攻击者直接把恶意镜像推到latest标签然后诱导节点拉取这就等于直接种了后门。下面是一段我在检查镜像历史层时常用的命令组合大家可以直接抄作业# 先把镜像导出并解包 docker save -o image.tar 镜像名:tag mkdir image_layers tar -xf image.tar -C image_layers # 逐个层查看遗漏的敏感文件 find image_layers -type f | xargs grep -l password\|secret\|token\|api_key 2/dev/null # 或者更简单点直接看环境变量配置 docker history --no-trunc 镜像名:tag | grep -i ENV\|secret\|key2.2 运行时逃逸与隔离失效镜像层的漏洞顶多是泄密运行时层的漏洞才可能直接垂直打到宿主机。容器逃逸的经典路径大概有几种内核漏洞逃逸基于内核CVE利用典型如Dirty COWCVE-2016-5195这一类内核写漏洞虽然老但有些内核版本一直没升级。容器运行时漏洞比如runC的CVE-2019-5736包括当时那个通过覆盖runtime环境变量来覆写二进制的方式在现代运行时里已经修复但很多企业内部还跑着非常老的Docker版本。特权容器与capabilities--privileged、CAP_SYS_ADMIN这类高危能力如果给了容器那逃逸路径几乎等于把宿主机内网敞开了。敏感挂载把/、/etc、/var/run/docker.sock这些宿主机目录挂载进容器是最常见的错误。只要容器内有root权限通过docker.sock就能创建特权容器接着逃逸是水到渠成的事。我在测试中遇到过一个特别典型的场景某个监控容器需要读取宿主机日志运维图方便直接挂载了宿主机的/var/run/docker.sock理由是“反正只是个统计容器没人会进来”。但那个容器跑的Web应用恰好有个SSRF漏洞攻击者通过SSRF请求unix:///var/run/docker.sock的API创建了一个挂载宿主机根目录的恶意容器然后直接把host的cron目录给改了。整个过程就是一条链路Web漏洞 → SSRF → Docker API权限 → 宿主机命令执行。所以运行时检测的优先级里我的经验是先看capabilities和挂载再看运行时版本和内核版本。前两者是配置问题往往比内核漏洞更容易利用、更不需要“拼运气”。2.3 容器配置层面的高危项前两年有份专业机构的报告显示云环境里配置错误导致的数据泄露数量比漏洞利用导致的还要多。我在做测试时也深有同感。用checklist的方式列一下我最常关注的配置容器以root运行默认UID为0一旦拿到shell就能在容器内提权再配合内核漏洞逃逸概率大增。hostNetwork和hostPID容器与宿主机共享网络或进程命名空间逃逸的难度直接降低一个档次。privileged: true这个不用解释了等于给了容器几乎全部内核能力。securityContext.capabilities比如NET_ADMIN、SYS_ADMIN、SYS_PTRACE每一个都可能成为逃逸跳板。readOnlyRootFilesystem未设置容器内可写文件系统攻击者落地持久化脚本更容易。allowPrivilegeEscalation未置false二进制本身可以setuid进一步帮助提权。我建议做安全测试时直接用kubeaudit这类工具自动过一遍配置基线然后手动验证高危项。自动扫出来的东西只能作为起点真正的高价值点在于“配置项与实际权限组合出来的利用链”。3. K8s安全攻防控制面、工作负载与网络策略K8s这块是云原生漏洞挖掘的高潮区。因为K8s本身就是一套复杂的分布式系统组件多、接口多、配置项更多任何一个组件的错误配置都可能成为攻击者横向移动的关键跳板。我先把控制面、工作负载和网络三个主要攻击路径拆开讲最后再加一个实战场景从SSRF漏洞到云凭证的完整链路。3.1 API Server、RBAC与服务账户令牌K8s的API Server是集群的大脑理论上只要控制了API Server的权限整个集群就是你的。所以API Server的安全测试重点是两个一是暴露面二是认证授权。暴露面很直观kube-apiserver的默认端口是6443很多企业部署后直接暴露在公网IP上而且出于运维方便开了--anonymous-authtrue。这不单意味着任何人都能访问API Server更严重的是如果RBAC模型里恰好给匿名用户授予了某些权限有些企业为了图省事设置了system:anonymous绑定到cluster-admin那就直接等于把集群全权交出去了。RBAC是另一个重点。我自己测试时会先枚举当前能访问到的ServiceAccount有哪些权限然后挨个看当前集群里有没有过度授权的情况。比如某个namespace下的Pod明明只需要读取自己的Pod列表却被授予了list secrets的权限。这种情况下攻击者只要攻进那个Pod就能把整个namespace下的所有Secret都拉走。这种越权在企业里的发生率非常高因为开发者的权限设计往往是“既然要读Pod那就顺便给个宽一点的角色吧”。ServiceAccount令牌的泄露也要重点关注。以前有段时间K8s 1.20之前默认挂载的ServiceAccount令牌永不失效等于所有Pod里都藏着一把长期有效的集群内钥匙。如果某个Pod允许外部流量打到某个暴露的路由比如一个Debug接口攻击者就能拿到令牌用这个令牌向API Server发请求。我在测试中就用这个方法从一个小Pod的令牌直接枚举出集群管理员权限。给大家一个快速验证某ServiceAccount权限的命令安全测试时非常实用# 先通过kubectl看当前账号有没有get secret的权限 kubectl auth can-i list secrets --namespace target-ns --assystem:serviceaccount:ns:sa # 如果有直接列出所有secret kubectl get secrets -n target-ns -o json | jq .items[].data | with_entries(.value | base64d)3.2 etcd、kubelet 与审计日志控制面的另外两个关键组件是etcd和kubelet。etcd存的是整个集群的配置和状态包括所有Secret明文值除非加密配置没开。很多企业的etcd监听在2379端口上而且没有认证配置只要能网络触达就能用etcdctl把整个集群的所有配置拉下来。我以前做测试遇到过一次etcd端口居然开在公网IP上我直接连上去把集群里的所有Secret、ServiceAccount令牌、Node信息全部拿到了画面非常美。所以etcd的防护一定是重中之重至少要做到网络隔离、TLS双向认证、开启Secret加密。kubelet的问题是很多版本默认的--anonymous-auth是真同事Port 10250的未授权访问漏洞曾经在不少云环境里是致命入口。攻击者可以直接远程调用kubelet的API读取节点上所有Pod的信息甚至在某些配置下直接(exec)进容器通过/run/{namespace}/{pod}/{container}/exec接口。这种“绕过K8s控制面直连节点”的路径在安全团队没有全面覆盖节点监控时非常隐蔽。审计日志这块我在测完漏洞之后一定会花时间看集群的审计策略开了没有、开到了什么级别、有没有把敏感请求如get secrets、exec操作记录下来。没有审计日志就算发生安全事件后续溯源和漏洞影响评估也会非常困难。很多企业出事之后应急响应做不了不是能力不行是压根没有日志可查。3.3 网络平面与SSRF的利用路径云原生环境下默认All Allow的网络策略是常态。这意味着任何Pod都可以访问集群内任何其他Pod的任何端口。攻击者只要拿下一个Pod就相当于获得了一个集群内部的跳板机可以自由探测内网的主机、数据库、其他服务。这里有一个特别经典的利用链外部Web应用的SSRF → 集群内网探测 → 云元数据服务 → 云凭证。这个“SSRF漏洞与云原生环境结合”的攻击路径覆盖率和成功率都非常高也是我在企业测试中特别爱用的切入方式。具体思路是这样的目标Web应用部署在Pod里然后有一个参数可以传入URL发起请求这就是一个SSRF漏洞。从Pod内部访问云厂商的元数据接口有的厂商是169.254.169.254有的厂商有自己的自定义地址可以拿到绑定的临时访问凭证。然后用这个凭证调用云API查看对象存储桶、云主机列表甚至直接读取其他云上的敏感资源。整理一下这个链路的要点供大家在做漏洞挖掘时参考先找目标应用的SSRF点Fuzz所有可能触发服务端请求的参数。用SSRF访问元数据接口确认云环境类型。拿到临时凭证后检查凭证的权限范围看看有没有对象存储读写权限。如果权限够大直接列举所有存储桶找敏感数据备份文件。整个过程记录好影响范围报告中写明从Web SSRF到云凭证的完整利用路径。这个链路之所以“香”是因为它跨越了Web漏洞、容器网络、云平台权限三个层次。只要业务方没有把网络策略收紧、没有给元数据服务设防护那么从Web打进来的攻击面就会很大。4. 企业级漏洞挖掘实操方法论与工具链前面讲了原理和攻击路径下面聊点更落地的实际做企业级云原生漏洞挖掘时我的操作流程和工具选型以及怎么借鉴SRC漏洞挖掘的思路提高产出效率。4.1 资产梳理与攻击面盘点很多人一上来就跑扫描器其实这是低效的。我个人的做法第一步永远是资产梳理——搞清楚目标到底有哪些集群、哪些镜像、哪些暴露的服务。这一步做好了后面所有测试才有边界报告也能写得更清楚。具体来说资产梳理阶段我会做三件事域名与IP摸底找出哪些IP开着6443、10250、2379这些K8s相关端口哪些域名解析到了负载均衡后面负载均衡后面到底藏着哪些后端服务。镜像清单通过镜像仓库API如果有权限或运维提供的资料列出所有业务镜像判断基础镜像版本和依赖情况。Pod与Namespace枚举拿到了控制面访问权限哪怕是一个受限SA后用kubectl枚举namespace、Pod、Service、ConfigMap和Secret的分布情况。资产梳理阶段还有一个用Python写的快速探测脚本的思路非常实用可以批量扫描IP段里的K8s端口并识别组件版本。比如import socket import re def check_k8s_api(ip, port6443): try: s socket.socket() s.settimeout(3) s.connect((ip, port)) # 发送一个HTTP OPTIONS请求看返回的Server头信息 s.send(bOPTIONS / HTTP/1.1\r\nHost: \r\n\r\n) resp s.recv(1024).decode(utf-8, errorsignore) # 匹配K8s API Server的特征 if Kubernetes in resp or Unauthorized in resp: return f[K8s] {ip}:{port} - {resp.splitlines()[0]} s.close() except Exception: pass return None这个脚本可以扩展成多线程版本再配合指纹识别做大规模资产摸底。当然实际操作中要注意授权的边界别扫到不属于客户授权的网段。4.2 常用工具链与选型工具这块我推荐的思路是自动扫描工具做初筛手工验证做深入利用。下面是我在测试中常用的工具按照场景分类列一张表场景工具作用镜像扫描Trivy、Grype扫描镜像内依赖、基础镜像漏洞、密钥泄露容器配置检查Docker Bench、kubeaudit检测特权容器、危险capability、目录挂载集群安全基线kube-bench对照CIS Benchmark检查集群配置集群攻击面侦察kube-hunter识别集群暴露面和可攻击路径运行时监控Falco实时检测容器内异常行为和逃逸事件手工利用辅助kubectl、k9s、etcdctl权限枚举、资源查看、etcd数据读取Trivy这里多说一句它的一个好处是可以扫IaCInfrastructure as Code里的配置问题比如Terraform、Helm Chart里的不规范配置。很多企业把集群配置写成了代码测试时把他们的Helm Chart拉下来扫一遍往往能直接发现配置层面的问题不用等部署之后再倒查。自动工具扫描完之后手工验证最重要。比如Trivy扫到容器里有个老的OpenSSL版本但实际这个容器的二进制里根本没有调用OpenSSL的程序那这个漏洞的利用价值就不高。反过来如果某个组件确实在监听网络端口且可被外部访问那么这个漏洞就要优先处理。这个验证的过程就是安全测试和单纯“报漏洞”的分水岭。4.3 借鉴SRC漏洞挖掘的思路提高效率SRC漏洞挖掘的思路和企业级授权测试是相通的核心区别只是授权范围和报告口径。SRC挖掘里最有效的一种思路叫“以小博大”找边缘系统的漏洞作为突破口然后横向往核心系统打。云原生环境下边缘系统往往是指那些攻击者能直接触达的Web服务——它们可能部署在同一个集群里但因为整个集群的网络策略未收紧一旦麻烦进入这些边缘Pod就能试探着访问内部的数据库、认证中心、管理后台。另一个SRC里非常重要的思路是“信息收集的厚度决定漏洞产出的高度”。我在测云原生环境时也一样会把OpenAPI文档、Swagger接口文档、配置中心暴露的JSON配置都拉出来挨个看。很多Pod的YAML里就写着环境变量里面直接有数据库连接串、API密钥。这不算扫描器能扫出来的东西但却是最容易造成严重影响的漏洞之一。最后报告撰写的细节也很重要。企业级漏洞报告尤其是挖到高危漏洞之后光写“API Server未授权访问”是不够的。我会在报告中附上完整的利用步骤用什么命令、拿到什么权限、能访问哪些敏感数据、影响范围有多大。另外还会附上修复建议包括具体配置项怎么改、涉及哪些对应版本的加固文档。这种报告交付之后客户才真正愿意去处理而不是放个低优先级。5. 常见问题与排查技巧实录做云原生安全测试这么久我碰到过不少奇奇怪怪的问题下面整理一份速查表并且挑几个多说两句。有些问题看着是环境部署的问题实际跟安全配置、资源隔离有千丝万缕的关系。5.1 测试与部署中的典型问题速查问题现象可能原因排查建议K8s Master初始化失败报“the api server is not healthy after 4m...”运行时或网络插件没就绪、Swap未关、容器镜像源拉取失败检查coredns、etcd容器状态确认kubelet日志关掉Swap容器内无法访问宿主机网络服务容器网络模式为bridge未用hostNetwork确认网络模式配置网络策略放行特定端口Trivy扫描没漏洞但Pod能被逃逸扫描仅覆盖镜像依赖没覆盖运行时配置补做capability和挂载检查参考Docker Bench容器资源隔离失效宿主机被某个容器拖垮未设置limits或cgroup版本不匹配为Pod配置request/limit升级节点cgroup版本审计日志查不到入侵痕迹审计策略级别过低或未开启开启审计至少设置为Metadata级别通过ServiceAccount访问API Server被拒绝RBAC未授权该SA操作对应资源用auth can-i检查权限补齐最小权限第一个问题“the api server is not healthy”是很多人搭集群时都会撞上的。这里面的原因多数不是安全漏洞而是部署细节比如Master节点开了Swapkubelet默认把Swap当作不安全行为直接拒绝再比如etcd其实没起得来结果API Server连不上后端的持久化层又比如容器运行时用的containerd和Docker并存cri接口没指对kubelet看不到Pod状态。这个问题一旦出现安全测试就没法进行所以我的建议是先把节点环境规范好关Swap、固定好运行时、确认cni网络插件先起来再去初始化集群。前面说的这些细节网上K8s安装部署的帖子踩坑区里基本都有但很少有人提醒“先把coredns跑起来再说后话”。第二个问题容器访问宿主机的网络环境这是很多边缘设备、监控Agent场景的刚需。企业里有两种做法第一种是直接用hostNetwork: true共享宿主机网络简单粗暴但副作用是宿主机端口容易被占用而且规避了网络策略的隔离第二种是用network_mode: host类似的做法。我建议对于需要访问宿主机特定监听端口的场景优先考虑配置NetworkPolicy只放行特定端口而不是直接共享整个网络命名空间。毕竟你也不知道这个容器被攻破之后攻击者会对宿主机内网做些什么。5.2 几个真实踩过的“程序坑”再分享几个我实际测试中遇到的细节问题坑一扫描工具漏报配置问题。Trivy默认扫描范围是OS包和语言依赖包但从前某一版本的Trivy会把密钥检测和IaC扫描作为内置功能默认却不全开。早期版本如果你的Trivy还没配置--detect-secrets或类似的扫描开关那么镜像里的AK/SK泄露是不会报出来的。所以不要迷恋默认配置按场景把所有扫描开关都打开再人工复核。坑二ServiceAccount权限枚举走偏。很多新人在枚举RBAC权限时喜欢用kubectl auth can-i --list但那个列出的是当前上下文的账号权限不是目标SA的权限。正确姿势是配合--as来模拟目标身份或者干脆用一些现成的权限枚举脚本。我测试时见过有人拿着一堆不存在的权限到处汇报“这里有漏洞”其实等他们连目标SA的真实权限都没看明白。坑三SSRF打到元数据服务被安全设备拦了。这个场景在企业里很常见因为有些云环境里元数据地址和DNS解析策略都变了加之还有MetaData防护机制比如青云等云的元数据隔离。我踩过一次后发现某些云平台通过imds服务配合网络策略做了过滤只有特定进程才能访问元数据接口。这种情况下的利用路径会更曲折比如先SSRF内网一台跳板机再通过跳板机访问元数据。所以在报告里要写明“受到xx限制需配合其他条件”避免夸大。5.3 一点经验性总结我在实际做云原生漏洞挖掘时最大的体会是漏洞挖掘的第一步不是扫描器而是搞清楚“这个世界是怎么互联的”。容器、Pod、Service、NetworkPolicy、Ingress、云元数据服务它们之间的信任关系才是攻击面所在。比如很多企业会把Redis、MongoDB这类单点服务直接放在Pod里没有负载均衡也没有认证然后通过ClusterIP暴露给集群内其他Pod。如果攻击者已经控制了某个Pod那么扫描内网里的ClusterIP 段基本就能看到所有敏感后端。而传统的漏扫工具对这类内网服务是“看不见的”所以必须把测试思路从“扫实例”转成“扫集群内网”。另外多从“配置漂移”的角度找问题。云原生环境里配置随时在变昨天加固过的集群今天可能因为一次Helm升级把SecurityContext给冲掉了。所以测试和运维都要养成把基线配置版本化的习惯出了事能快速对比出“从哪一次变更开始不安全”。最后再提一点做云原生安全不只是安全团队的事开发、运维、K8s管理员都得卷进来。镜像是怎么构建的、Helm Chart是谁提交的、某个Secret是谁更新过的这些流程里的每一个环节都可能埋下隐患。我接触过的很多案例最后根因不是某一行配置写错而是整个流程里没人对安全配置负责。这一点比挖出一个漏洞本身更值得反思。
返回列表