利用SSRF漏洞泄露机密API密钥
服务器端请求伪造(SSRF)是一种安全漏洞类型,其本质是诱骗服务器向非预期主机发送网络请求。在某些情况下(如Scott Helme的安全头部工具),允许用户触发从某些后端到任意主机的HTTP请求是一项功能。但在许多其他情况下,这是一个严重的安全漏洞,可能使攻击者对易受攻击服务器背后的组织造成严重破坏。
一个有趣的代理
这一切始于一个引人注目的代理。为了促进钱包操作,该应用向用户提供当前汇率,这些汇率会在UI中定期刷新。通过Burp检查网络流量时,我注意到以下形式的请求:
|
|
URL路径中包含另一个URL(而不是查询字符串中)让我感到奇怪,这似乎是漏洞潜伏的好地方。
代理的角色
查阅CoinMarketCap API文档后,我找到了答案:
目前禁止在客户端使用JavaScript进行HTTP请求[…]。这是为了保护您的API密钥,不应让应用程序用户看到,以免API密钥被盗。通过您自己的后端服务路由调用来保护API密钥。
这很有道理。因为使用CoinMarketCap API需要付费账户和保密的API密钥,目标不能简单地从其前端查询API:这样做确实会迫使目标在其客户端源代码中披露其API密钥。
一个令人惊讶的简单绕过
如果我能够伪造一个发送到我控制的主机的请求,我可能能够披露敏感信息,包括目标的CoinMarketCap API密钥。经过一些测试,我很快注意到一个有趣的行为:每当我提交以https://pro-api.coinmarketcap.com
开头的URL时,代理会响应502 Bad Gateway,而不是200 OK或400 Bad Request。
我解释这种可观察到的行为差异为提示,代理只要求用户提供的URL具有预期的前缀:如果有,代理将服从并尝试向指定主机发送请求。为了证实我的直觉,我决定运行另一个测试,这次指定预期主机但将方案从https替换为http:
|
|
非常有希望!这向我表明,绕过代理不小心的URL验证确实是可能的。
利用@符号进行误导
正如James Kettle(又名albinowax)所写:
经常被忽视的使用@创建误导性URL的能力经常有用。
通过向URL的主机部分追加@attacker-site.com
,你通常可以诱使不小心的服务器向attacker-site.com发送请求,而不是最初预期的主机。这个技巧一次又一次地对我有效,这次也不例外。
通过发出以下请求,我再次能够从代理获得502 Bad Gateway响应:
|
|
通过代理发现的内容
相关的日志条目包含一些次要重要性的信息。特别地,我了解到我的伪造请求包含以下头部:
|
|
这揭示了代理是用Node.js编写的,并使用NPM模块node-fetch来使用CoinMarketCap API。
当然,目标的CoinMarketCap API密钥是真正的奖品;它就在一个名为X-CMC_PRO_API_KEY
的头部中。我启动curl并使用刚从目标窃取的API密钥向https://pro-api.coinmarketcap.com/v1/key/info
发送GET请求。
响应显示目标使用的是CoinMarketCap的Startup计划,该计划施加了一些速率限制,并为订阅者提供适度的每日信用额度。一个粗略的计算告诉我,攻击者可以在不到12分钟内耗尽目标的每日信用额度,从而剥夺目标在当天剩余时间内获取最新汇率的能力。
解决方案
我向目标报告了我的发现,并敦促他们在修复代理的URL验证后撤销其CoinMarketCap API密钥。我得到了目标的及时和感激的回复,最终奖励了我当时价值约1000美元的加密货币代币。
结论
如果您是开发人员,请不要轻视URL解析:它通常对安全至关重要,但充满危险。使用经过验证的URL解析库,而不是依赖普通或自定义的字符串处理函数。
如果您是一名初出茅庐的黑客,我希望这篇文章激发了您对服务器端请求伪造的兴趣。如果您想更深入地了解粗糙的URL解析和SSRF之间的相互作用,您会喜欢Orange Tsai在DEF CON 25上的演讲。