利用CoreDNS枚举集群Service & Port & 解决方案

本文为技术探讨文章,文中只提供思路,并不提供攻击脚本。

0. 关于云原生渗透

在新型网络架构当中,云原生可以说是新型应用部署方式的一颗明星,很多公司都在积极的建设自己的云原生体系,在云原生体系的建设当中,云原生安全是至关重要的,而提到了云原生安全那就不得不提云原生渗透了。

并不是所有的云原生渗透都能通过简单的容器逃逸来进行,在对单一容器的渗透进行不下去的时候,选择结束渗透是很不明智的选择,因为除了无安全隐患的容器,集群内还可能存在有安全隐患且符合逃逸条件的容器,这样就涉及到容器之间的横向攻击了。在基础的K8s集群当中,并不能使用ICMP协议进行容器发现,例如下图:

所以如何进行容器发现成了云原生渗透的一个难题。

1. 发现

  1. 早些时间在看CoreDNS代码的过程中,发现在/pkg/dnsutil/reverse.go存在关于in-addr.arpa的定义。

跟了一下,走到 /plugin/hosts/hosts.go ,发现CoreDNS是支持PTR解析记录的。

看下k8s_external包,这个包是处理svc域名的一些操作。109行发现K8s插件也是支持ptr记录的,CoreDNS的使用过程是集群内部的域名,coreDNS分发至kubedns,集群外的域名则通过coreDNS进行递归。

2. 利用

在公共DNS服务器上,很少会有ip存在PTR解析记录,而集群内部所有的域名都是通过Service进行管理,这样也就说明,如果CoreDNS的K8s插件若支持PTR记录,那么集群内部就可以通过ip来获取svc域名:

正常情况下,查询一个service的A记录是这样的:

复制代码
<SVC>.<NAMESPACE>.svc.cluster.local

若PTR可用,我们将会得到重要的三个信息,一个是命名空间、一个是svc名称、一个就是svcip,事实证明,这条路可行。

那么按照这个思路,就可以通过PTR记录进行所有的Service的枚举了。

3. 实现

在集群容器内部,由于需要使用CoreDNS,/etc/resolv.conf文件会与普通的机器不同:

由于K8s配置过程中需要将CoreDNS与svc放在同一个网段,这样一来,通过容器内部的**/etc/resolv.conf**文件就可以知道集群svc所在ip段,通过Fuzz这个段所有的ip将会得到完整的svc情况。

根据这个原理,写了个脚本,去跑所有svc地址。

一个B段6000并发下仅需要几秒。

4. 端口探测

以上的所有操作是将所有的svc名字、命名空间以及ip地址枚举了出来,但是在svc当中还有一个重要信息,那就是端口,其实按照上文描述的方法已经可以对存活svc进行端口扫描了,但是就这么做的话,不优雅,因此再次打开CoreDNS的代码,找找优雅的办法。

/plugin/k8s_external/external.go 107行

这是允许通过的四种dns类型,A为 域名-ip4;AAAA为 域名-ip6;PTR为 ip-域名;SRV为 服务-端口。

前三种已经都被我们所利用了,唯独第四种SRV记录还没被使用。

SRV记录

英语:Service Record ,中文又名服务定位记录是域名系统中用于指定服务器提供服务的位置(如主机名和端口)数据。此数据于RFC 2782中定义,类型代码为33。部分协议,如会话发起协议(SIP)及可扩展消息与存在协议(XMPP)通常需要服务记录的支持。

正常使用是这样的:

复制代码
nslookup -qt=srv _<service>._<proxy>.domain.com

在集群当中测试下:

按照这个写法不行,但是代码中写了,说明肯定是支持的,把svc、命名空间、协议进行排列组合,看哪一种是可行的。最终发现,集群内的srv域名查询需要符合以下格式。

复制代码
nslookup -qt=srv <svc>.<namespace>.svc.cluster.local

其中30111端口的,即为svc开放端口。

将这个东西融入之前的脚本,达到如下效果。

复制代码
{"default":[{"SVC":"kubernetes","IP":"10.1.0.1","Port":[443]}],"kube-system":[{"SVC":"kube-dns","IP":"10.1.0.10","Port":[9153,53]}],"moresec-system":[{"SVC":"****-fileserver","IP":"10.1.3.195","Port":[7777]},{"SVC":"******","IP":"10.1.8.79","Port":[6379]},{"SVC":"*****-****-service","IP":"10.1.12.127","Port":[443]},{"SVC":"*****-********","IP":"10.1.53.252","Port":[27017]},{"SVC":"*******-*****-manager","IP":"10.1.1.43","Port":[5020]},{"SVC":"******-********","IP":"10.1.59.129","Port":[8010,5006]},{"SVC":"*******-******","IP":"10.1.56.115","Port":[8090]},{"SVC":"***-*******","IP":"10.1.72.216","Port":[***]},{"SVC":"*****-******-manager-proxy","IP":"10.1.88.58","Port":[8080]},{"SVC":"******-******","IP":"10.1.92.117","Port":[9001,9000]},{"SVC":"******-*****-srv","IP":"10.1.95.161","Port":[5002]},{"SVC":"******-scanner","IP":"10.1.139.11","Port":[5103]},{"SVC":"****-*****-******","IP":"10.1.213.112","Port":[8080]},{"SVC":"*****-*****","IP":"10.1.222.32","Port":[5040]},{"SVC":"******-*****","IP":"10.1.245.240","Port":[443]},{"SVC":"******-*****","IP":"10.1.255.210","Port":[4151,4150]}],"work":[{"SVC":"tomcat8","IP":"10.1.229.92","Port":[80]}],"zhuri":[{"SVC":"tp-svc","IP":"10.1.0.47","Port":[15443]},{"SVC":"tomcat-svc","IP":"10.1.34.246","Port":[9080]},{"SVC":"baota-svc","IP":"10.1.47.228","Port":[18800,18080,18888]},{"SVC":"sqli-svc","IP":"10.1.224.165","Port":[18081]}]}

这样就优雅了很多。但是值得一提的是,这个方法拉出的port不区分tcp udp,但是就我使用过的几个集群来讲,除了CoreDNS以外,很少会有udp端口的出现,但具体情况根据集群业务来看。

5. 解决

对于业务不需要srv与ptr记录的集群,禁用coreDNS的ptr与srv记录。

复制代码
#修改CoreDNS的配置文件
kubectl edit configmap/coredns -n kube-system

加入如下两句配置:

经过该配置,CoreDNS会拦截掉ptr与srv记录。

相关推荐
哈里谢顿15 小时前
Kubernetes Operator核心概念、实现原理和实战开发
云原生
阿里云云原生20 小时前
你的 OpenClaw 真的在受控运行吗?
云原生
用户9623779544820 小时前
DVWA 靶场实验报告 (High Level)
安全
阿里云云原生21 小时前
5 分钟零代码改造,让 Go 应用自动获得全链路可观测能力
云原生·go
Shanyoufusu1221 小时前
RKE2 单节点集群安装 Rancher+ 私有镜像仓库搭建 完整教程
云原生
阿里云云原生1 天前
Dify 官方上架 Higress 插件,轻松接入 AI 网关访问模型服务
云原生
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
AI攻城狮1 天前
OpenClaw Session 管理完全指南:Context 压缩、重置与持久化
人工智能·云原生·aigc
用户962377954481 天前
DVWA 靶场实验报告 (Medium Level)
安全