flawopen.com/Incidents/capital-one-ssrf-imds-july-2019
●
Capital One · CWE-918 · July 2019 · 严重
安全研究 · FlawOpen
Capital One SSRF:窃取 AWS IMDSv1 凭据
联邦刑事诉状称,配置错误的 WAF 使 SSRF 能访问 AWS IMDSv1,暴露了临时角色凭证及约 1.06 亿人的 S3 数据。应强制令牌并限制角色权限。[10], [2]
💡 通俗易懂的原理解析 (ELI5)
DOJ 刑事诉状指称的链路可以这样理解:想象一位前台接待员,你告诉她地址后,她就会去取文件。请求转发可能让别人把她引到内部办公室。她在那里可以取得工作负载的临时通行证;通行证只能进入关联角色获准访问的房间。问题在于设计者以为只有员工能到办公室,却忽略了接待员可以被引导过去。[10], [8]
核心概念与专有名词
SSRF- 服务端请求伪造(
CWE-918):让服务器发出攻击者选定的请求,使该请求带上服务器的网络位置和信任。[9] Web 应用防火墙- 部署在 Web 应用前的过滤器。刑事诉状称,Capital One 配置错误的 WAF 可被诱导将请求转发至内部地址。[10]
IMDSv2- IMDSv2 使用通过 PUT 请求获取的会话令牌。设置
HttpTokens=required可拒绝不带令牌的 IMDSv1 请求;这能阻止许多只能发送普通 GET 的 SSRF 转发,但不能彻底防止 SSRF。[7], [6] IAM 角色凭据- 签发给实例的临时 AWS 密钥。角色能做的事,持有密钥的人在其过期前都能做。[8]
框架映射
- 本指南所述弱点的 CWE 参考: CWE-918
- D3-OTF 出站流量过滤 — 本指南中的出站网络限制会限制服务或主机可访问的目标。
事件演进时间线
2019-07-17
一名外部研究人员通过 Capital One 的负责任披露计划报告了外泄的数据。[2]
2019-07-29
Capital One 公布事件,FBI 在西雅图逮捕一名嫌疑人。[1]
攻击执行流程分解
源代码对比:漏洞与安全实现
这是 Flask 示例代码,并非 Capital One 的配置。主机名允许列表是应用层的主要控制。必需的出口代理必须在连接时针对解析后的地址执行策略,阻止私有和链路本地网段(包括实例元数据服务),并对每个请求及重试均重复检查;请核实代理配置确实如此。代码不会跟随重定向。若应用先单独解析 DNS 再连接,仍会留下 DNS 重绑定竞态。[9], [5], [6]
存在漏洞的实现
import requests
from flask import Flask, request
app = Flask(__name__)
@app.get("/fetch")
def fetch():
# 服务器会获取调用方提供的任意 URL。
url = request.args["target"]
resp = requests.get(url, timeout=5)
return resp.text
加固后的安全修复
from urllib.parse import urlsplit
import requests
from flask import Flask, abort, request
app = Flask(__name__)
ALLOWED_HOSTS = {"images.example-cdn.com", "api.partner.example"}
EGRESS_PROXY = "http://egress-proxy.internal:3128"
# 配置此代理,使其在 DNS 解析后执行目标策略。
@app.get("/fetch")
def fetch():
parts = urlsplit(request.args.get("target", ""))
if parts.scheme != "https" or parts.hostname not in ALLOWED_HOSTS:
abort(400, "destination not allowed")
if parts.port not in (None, 443) or parts.username or parts.password:
abort(400, "destination not allowed")
resp = requests.get(parts.geturl(), timeout=(2, 5), allow_redirects=False, proxies={"https": EGRESS_PROXY}, trust_env=False)
if resp.is_redirect:
abort(502, "upstream redirect refused")
return resp.text
工程与系统安全加固清单
- ✓通过出口代理转发 URL 请求,并在连接边界执行主机允许列表和 IP 网段策略:只连接已检查的地址,并在重试时重复应用策略。禁用重定向,或重新验证每一跳;仅阻止字符串 169.254.169.254 并不足够。[9], [4]
- ✓对每个适用实例设置
HttpTokens=required,并检查现有实例,因为账户默认值不会自动更新每个实例。根据工作负载的网络路径选择HttpPutResponseHopLimit;AWS 警告值为 1 时容器可能出现问题。令牌要求会拒绝 IMDSv1 请求;跳数限制是独立的网络路径设置,并非阻止无令牌 GET 的控制。[6], [7] - ✓刑事诉状称,SSRF 路径暴露了实例角色。将该角色限制为工作负载所需的操作和资源,避免凭证泄露带来无关的 S3 访问权限。[10], [8]
- ✓FlawOpen 检测建议:当临时角色凭证在实例网络之外使用时发出告警,并结合工作负载及云审计上下文进行调查。
- ✓代码评审时,凡是用户能影响服务器所抓取 URL 的路径,都要像用户能影响 SQL 查询的路径一样对待,并要求为其编写白名单测试。[9], [5]
参考来源
- 美国司法部 — 西雅图一名科技从业者因窃取大型金融服务公司数据被捕(2019 年 7 月 29 日)
- Capital One — 关于 2019 年网络安全事件的说明
- OCC — 因 2019 年事件对 Capital One 处以民事罚款(2020 年 8 月)
- 为什么 SSRF 在云环境中如此危险?
- fetch() 会导致 SSRF 吗?
- AWS — Configure the Instance Metadata Service options
- AWS — Use the Instance Metadata Service to access instance metadata
- AWS — Retrieve security credentials from instance metadata
- OWASP — Server Side Request Forgery Prevention Cheat Sheet
- DOJ — United States v. Paige Thompson, criminal complaint (29 July 2019)