AWS - EKS Post Exploitation

Reading time: 6 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

EKS

Per maggiori informazioni consulta

AWS - EKS Enum

Enumerare il cluster dalla AWS Console

Se hai il permesso eks:AccessKubernetesApi puoi visualizzare oggetti Kubernetes tramite la console AWS EKS (Scopri di più).

Connettersi al cluster Kubernetes AWS

  • Metodo semplice:
bash
# Generate kubeconfig
aws eks update-kubeconfig --name aws-eks-dev
  • Non è così semplice:

Se puoi ottenere un token con aws eks get-token --name <cluster_name> ma non hai i permessi per ottenere le informazioni del cluster (describeCluster), puoi preparare il tuo ~/.kube/config. Tuttavia, avendo il token, ti serve comunque l'endpoint URL a cui connetterti (se sei riuscito a ottenere un JWT token da un pod leggi here) e il nome del cluster.

Nel mio caso, non ho trovato le informazioni nei log di CloudWatch, ma le ho trovate in LaunchTemaplates userData e anche nelle macchine EC2 in userData. Puoi vedere queste informazioni in userData facilmente, per esempio nel seguente esempio (il nome del cluster era cluster-name):

bash
API_SERVER_URL=https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-east-1.eks.amazonaws.com

/etc/eks/bootstrap.sh cluster-name --kubelet-extra-args '--node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=1,alpha.eksctl.io/cluster-name=cluster-name,alpha.eksctl.io/nodegroup-name=prd-ondemand-us-west-2b,role=worker,eks.amazonaws.com/nodegroup-image=ami-002539dd2c532d0a5,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=prd-ondemand-us-west-2b,type=ondemand,eks.amazonaws.com/sourceLaunchTemplateId=lt-0f0f0ba62bef782e5 --max-pods=58' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP --use-max-pods false
kube config
yaml
describe-cache-parametersapiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1USXlPREUyTWpjek1Wb1hEVE15TVRJeU5URTJNamN6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTDlXCk9OS0ZqeXZoRUxDZGhMNnFwWkMwa1d0UURSRVF1UzVpRDcwK2pjbjFKWXZ4a3FsV1ZpbmtwOUt5N2x2ME5mUW8KYkNqREFLQWZmMEtlNlFUWVVvOC9jQXJ4K0RzWVlKV3dzcEZGbWlsY1lFWFZHMG5RV1VoMVQ3VWhOanc0MllMRQpkcVpzTGg4OTlzTXRLT1JtVE5sN1V6a05pTlUzSytueTZSRysvVzZmbFNYYnRiT2kwcXJSeFVpcDhMdWl4WGRVCnk4QTg3VjRjbllsMXo2MUt3NllIV3hhSm11eWI5enRtbCtBRHQ5RVhOUXhDMExrdWcxSDBqdTl1MDlkU09YYlkKMHJxY2lINjYvSTh0MjlPZ3JwNkY0dit5eUNJUjZFQURRaktHTFVEWUlVSkZ4WXA0Y1pGcVA1aVJteGJ5Nkh3UwpDSE52TWNJZFZRRUNQMlg5R2c4Q0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZQVXFsekhWZmlDd0xqalhPRmJJUUc3L0VxZ1hNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBS1o4c0l4aXpsemx0aXRPcGcySgpYV0VUSThoeWxYNWx6cW1mV0dpZkdFVVduUDU3UEVtWW55eWJHbnZ5RlVDbnczTldMRTNrbEVMQVE4d0tLSG8rCnBZdXAzQlNYamdiWFovdWVJc2RhWlNucmVqNU1USlJ3SVFod250ZUtpU0J4MWFRVU01ZGdZc2c4SlpJY3I2WC8KRG5POGlHOGxmMXVxend1dUdHSHM2R1lNR0Mvd1V0czVvcm1GS291SmtSUWhBZElMVkNuaStYNCtmcHUzT21UNwprS3VmR0tyRVlKT09VL1c2YTB3OTRycU9iSS9Mem1GSWxJQnVNcXZWVDBwOGtlcTc1eklpdGNzaUJmYVVidng3Ci9sMGhvS1RqM0IrOGlwbktIWW4wNGZ1R2F2YVJRbEhWcldDVlZ4c3ZyYWpxOUdJNWJUUlJ6TnpTbzFlcTVZNisKRzVBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-west-2.eks.amazonaws.com
name: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
contexts:
- context:
cluster: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
user: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
name: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
current-context: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
kind: Config
preferences: {}
users:
- name: arn:aws:eks:us-east-1:<acc-id>:cluster/<cluster-name>
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- --region
- us-west-2
- --profile
- <profile>
- eks
- get-token
- --cluster-name
- <cluster-name>
command: aws
env: null
interactiveMode: IfAvailable
provideClusterInfo: false

From AWS to Kubernetes

Il creator del EKS cluster potrà SEMPRE accedere alla parte del cluster kubernetes del gruppo system:masters (k8s admin). Al momento della stesura non esiste un modo diretto per scoprire chi ha creato il cluster (puoi controllare CloudTrail). E non esiste alcun modo per rimuovere quel privilegio.

Il modo per concedere accesso a K8s a più AWS IAM users o roles è usando la configmap aws-auth.

warning

Quindi, chiunque abbia accesso in scrittura alla config map aws-auth sarà in grado di compromettere l'intero cluster.

Per maggiori informazioni su come concedere privilegi extra a IAM roles & users nello stesso o in un account diverso e come abusarne per fare privesc check this page.

Vedi anche this awesome post per capire come funziona l'autenticazione IAM -> Kubernetes.

From Kubernetes to AWS

È possibile permettere un'autenticazione OpenID per i kubernetes service account per consentire loro di assumere ruoli in AWS. Scopri come this work in this page.

GET Api Server Endpoint from a JWT Token

Decodificando il token JWT otteniamo il cluster id e anche la regione. image Sapendo che il formato standard per l'url EKS è

bash
https://<cluster-id>.<two-random-chars><number>.<region>.eks.amazonaws.com

Non ho trovato alcuna documentazione che spieghi i criteri per i 'due caratteri' e il 'numero'. Però, facendo alcuni test per mio conto, vedo ricorrere questi:

  • gr7
  • yl4

Comunque sono solo 3 caratteri: possiamo eseguire il bruteforce su di essi. Usa lo script qui sotto per generare la lista

python
from itertools import product
from string import ascii_lowercase

letter_combinations = product('abcdefghijklmnopqrstuvwxyz', repeat = 2)
number_combinations = product('0123456789', repeat = 1)

result = [
f'{''.join(comb[0])}{comb[1][0]}'
for comb in product(letter_combinations, number_combinations)
]

with open('out.txt', 'w') as f:
f.write('\n'.join(result))

Poi con wfuzz

bash
wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws.com

warning

Ricorda di sostituire & .

Bypass CloudTrail

If an attacker obtains credentials of an AWS with permission over an EKS. If the attacker configures it's own kubeconfig (without calling update-kubeconfig) as explained previously, the get-token doesn't generate logs in Cloudtrail because it doesn't interact with the AWS API (it just creates the token locally).

So when the attacker talks with the EKS cluster, cloudtrail won't log anything related to the user being stolen and accessing it.

Note that the EKS cluster might have logs enabled that will log this access (although, by default, they are disabled).

EKS Ransom?

Di default lo user or role that created un cluster avrà ALWAYS admin privileges sul cluster. E questo è l'unico accesso "secure" che AWS avrà sul Kubernetes cluster.

Quindi, se un attacker compromette un cluster usando fargate e rimuove tutti gli altri admins e elimina lo AWS user/role che ha creato il Cluster, the attacker could have ransomed the cluster.

tip

Nota che se il cluster stava usando EC2 VMs, potrebbe essere possibile ottenere privilegi Admin dal Node e recuperare il cluster.

In realtà, se il cluster usa Fargate potresti creare EC2 nodes o spostare tutto su EC2 nel cluster e recuperarlo accedendo ai tokens nel node.

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks