SSRF绕过新思路:利用开放重定向突破内网访问限制 1. 这个靶场到底考什么题目拆解与核心思路先说结论这道题表面上考的是 SSRF服务端请求伪造实际上真正卡人的点在“怎么让服务器跟着你的思路跳转”。如果你不了解开放重定向Open Redirect的利用姿势很可能在过滤器这一层就卡死拿着 payload 疯狂试 IP 和域名结果全部被拦。PortSwigger 靶场也就是 Web Security Academy里的这道题属于 SSRF 系列的进阶关卡。题目环境大致是这样的某应用提供了一个库存查询功能你可以指定一个 URL让服务端去请求并加载商品图片。但如果直接访问内网地址或者本机回环地址会被一套服务端侧的过滤器直接拦下来。题目目标很明确访问http://192.168.0.12:8080/admin并删除某个用户。这里有一个常见的误区很多人一看到 SSRF 就习惯性去试127.0.0.1、localhost、2130706433这种数值 IP或者尝试 DNS 重绑定之类的骚操作。但这道题坑就坑在过滤器并不是简单地从 URL 里提取 hostname它会对整个 URL 做规范化解析然后再校验。你用的那些编码、十进制 IP 或十六进制 IP大部分在解析环节就被还原成真实地址然后被拦。所以你需要换一个思路。让服务端最终访问到真实目标但传入的参数却是一个“合法”的域名。怎么做到如果有一个合法域名在访问它时会自动 302 跳到192.168.0.12:8080那过滤器看到的只是那个合法域名就不会拦截。这就是开放重定向存在的意义。再看题目给出的线索某些已知的品牌跳转接口或者历史遗留的redirect参数恰好没有做白名单校验。于是整个解题链路就变成了找到一个存在开放重定向的合法入口。构造一个带有重定向参数的 URL让它能跳到内网地址。把这个 URL 作为 SSRF 的目标喂给服务端。服务端去请求这个 URL被重定向到内网过滤器完美绕过。整个过程听起来简单但实际操作中会踩到很多细节坑——比如重定向参数的位置、URL 编码处理、服务端和浏览器对重定向的解析差异等。后面的章节我会把这些细节逐一拆开讲。这道题的易错点还在于很多人不知道开放重定向漏洞本身其实就是个“合法后门”。在真实业务中第三方登录、营销活动和统一身份认证服务里这类跳转很常见——用户点一个链接应用引导它跳到 OAuth 授权页面或扫码登录页完成后重定向回业务入口。如果没有做好域名白名单校验谁都能用它做跳板。而在这道题里这个跳板恰好能被用来绕过 SSRF 过滤器。2. 开放重定向漏洞看似人畜无害的跳板2.1 什么是开放重定向为什么它能成为 SSRF 的“合法外衣”开放重定向Open Redirect指的就是一个应用接受了url、redirect、next、return这类参数然后直接用它作为跳转目标却不对目标域名做任何限制。攻击者可以构造一个看起来指向合法域名的链接比如https://合法域名.com/login?redirecthttps://evil.com诱骗用户点击最终把用户带到钓鱼页面。这是它最经典的利用方式。但在 SSRF 场景下它的“价值”完全不同。服务端请求某个 URL 时如果目标返回 302 重定向大多数 HTTP 客户端库包括 Python 的requests、Node 的axios、Java 的HttpClient以及很多应用自封装的网络请求模块默认会跟着重定向继续请求。也就是说只要第一步请求的 URL 通过了过滤器的校验后面的重定向目标就几乎不受过滤器约束了。生活化地理解过滤器相当于小区门口的保安。保安只认你出示的门禁卡不管进去之后你会拐到哪栋楼。开放重定向就是那张“合法门禁卡”——你拿出一个看起来完全正常的地址保安放行然后大门里面的路径就没人管了。这里的关键点在于开放重定向的终点完全由攻击者指定。所以它天然就是一个通用的“跳板”可以把 SSRF 的目标从一个合法域名转换成任意内网 IP。而更妙的是整个转换过程由目标服务器自己完成过滤器只看到了第一步的合法域名。2.2 为什么不是所有重定向都能用来绕过过滤器既然重定向这么好用一个问题自然冒出来任何 302 跳转都能拿来绕过吗答案显然不是。这里有一个容易被忽略的差异——谁能控制跳转目标。有些跳转是应用内部的固定逻辑比如用户没登录就跳转到/login页面。这种跳转的目标是写死在代码里的你改不了所以没法用来做跳板。真正的“开放重定向”必须满足一个条件跳转目标由外部输入控制。常用的载体包括显式参数如?redirectxxx、?nextxxx、?urlxxx、?returnxxx路径型跳转如/link?targethttps://xxx或//evil.com这种双斜杠表单提交后的跳转目标字段如form_action、callback_url在靶场里你发现了一个路径类似/product/nextProduct?path的接口其中path参数直接被拼到了重定向目标里而且没有任何协议和域名的限制。这就是天然的跳板。还有第二个差异客户端是否自动跟随重定向。浏览器默认跟随但应用代码不一定。有些应用为了安全会把自动跟随关掉然后手动处理重定向逻辑。所以在实际测试时你需要确认服务端确实会跟着 302 走。建议的做法是先用一个你完全可控的外部服务器比如你自己的 VPS 或公网请求记录服务来观察是否收到了来自目标服务的请求。如果收到了说明自动跟随是开启的如果没有要么是重定向参数没生效要么是服务端禁用了自动跟随。这个检查步骤非常关键。如果跳过它直接构造内网跳转 payload大概率等半天啥反应都没有还以为自己被拦截了其实是方向错了。3. 靶场通关实操从探测到拿 Flag 的全链路演示3.1 第一步分析靶场环境与确认 SSRF 注入点所有 Web 安全测试的第一步都一样先理清攻击面。进入靶场实验室环境后你要先确认几个问题哪个功能会触发服务端请求这个请求的参数如何构造服务端请求是 GET 还是 POST响应结果是否会在页面上反馈打开靶场主页面后可以看到一个正常的电商预览界面有商品信息、库存查询等功能。如果做过其他 SSRF 题目第一反应肯定是去找那种“检查库存”的接口因为它通常需要向某个外部系统发请求来获取数据。确认注入点的方法是拦截“Check stock”按钮发出的请求。用 Burp Suite 抓包后可以看到 POST 请求体里有一个参数内容是一个 URL 地址比如stock.host:8080或者类似形式。含义就是当前服务端会请求这个 URL 并显示结果。这一步的核心价值在于明确整个请求的完整链路。如果只看发包方向你根本不知道服务端是用什么库发请求的、会不会跟随重定向、对 URL 的校验是偏紧还是松。这些信息都需要你通过多次交互来验证。确认了注入点后先做一个最简单的 SSRF 连通性测试把这个参数的值改成http://192.168.0.12:8080/。如果过滤器直接拦截并报错恭喜你现在你知道了过滤器的存在。如果页面返回了管理页面的部分内容或者超时说明没有过滤器题目就简单多了——但既然题目叫“绕过过滤器”大概率你是会遇到拦截的。实测中很多初学者在这一步就以为失败了开始疯狂换 IP 编码。其实这一步的价值只是“确认过滤器存在”真正的解题关键在于下一步寻找跳板。3.2 第二步发现可用的开放重定向入口现在要找到靶场里可用的开放重定向点。这个环节依赖的是对 Web 应用结构的观察力而不是盲目爆破。假如靶场的某个功能是商品页跳转——比如“点击查看下一商品”的链接URL 长这样/product/nextProduct?currentProductId1path/product?productId2你突然发现path参数不仅决定跳转到哪个页面还影响了服务端的响应头里的 Location 字段。这就非常可疑了。试一下把path改成完整的外部 URL/product/nextProduct?currentProductId1pathhttp://your-server.com如果浏览器或者 Burp 的重定向跟随已经自动跳到了http://your-server.com那就说明这个参数没有任何域名校验它有开放重定向。这里有个实操技巧不要直接拿pathhttp://192.168.0.12:8080/admin去尝试万一这个跳转逻辑对 URL 有过滤你就在打草惊蛇。先用一个受控的外部域名测试确认它确实支持重定向到任意 URL。确认后再把目标替换成内网地址。再补充一种更隐蔽的测试方法把path改成//your-server.com。这利用了 URL 解析的一个特性——协议相对 URL。//开头会被浏览器和服务端解析为“使用当前协议并跳转到这个域名”。如果服务端对path参数做了“必须包含 http(s)”的校验这种写法可以绕过去——因为字符串里没有出现 “http”但解析结果却是一个完整的 URL。3.3 第三步构造完整的 SSRF 绕过链找到开放重定向入口后接下来的工作就是把整个绕过链串联起来。核心思路将最终 SSRF 的目标地址从内网 IP 替换成那个开放重定向 URL。具体构造如下原始 SSRF 请求的目标是http://stock.host:8080或者其他被允许的地址。替换为http://合法域名/product/nextProduct?currentProductId1pathhttp://192.168.0.12:8080/admin服务端去请求这个 URL。这个 URL 返回 302Location 头部指向http://192.168.0.12:8080/admin。服务端跟随重定向访问到了管理后台。实际发送的 POST 请求体可能是这样的stockApihttp://合法域名/product/nextProduct?currentProductId1%26pathhttp://192.168.0.12:8080/admin注意参数符号在 POST 数据里必须编码为%26否则服务端会把path误解为stockApi参数的兄弟参数而不是整个 URL 的一部分。这是一个极其常见的坑十个人里有八个在这里翻车。发送后看响应。如果一切顺利页面上会出现一个管理后台界面有若干用户账号其中一个好像是目标管理员账号。点击“删除”按钮或者直接构造删除请求即可完成题目。如果你发现响应还是被拦截了请做两个检查是不是path参数的值里包含内网 IP 导致被过滤如果是尝试把内网 IP 进行 URL 编码后再传入。是不是服务端在跟随重定向时做了二次校验如果是考虑改用 302 跳转而不是 301因为有些过滤器只跟 302。3.4 第四步从管理后台到完成删除操作拿到管理后台访问权后剩下的步骤就是标准操作。管理页面里通常有一列用户列表旁边有删除按钮。点击删除目标用户后靶场就会弹出“恭喜完成”的提示。这里有一个小经验删除操作可能也是一个独立接口直接通过 GET 或 POST 请求就能触发。如果你不熟悉页面操作直接发请求也没问题。抓住题目要求的那条线索——比如用户 ID 或者用户名——然后把请求发过去观察响应码和响应体。到了这一步整个攻击链才算完整闭环SSRF - 开放重定向 - 内网访问 - 管理操作。每一步都有自己的细节漏掉任何一个都可能功亏一篑。4. 容易翻车的 5 个细节高发踩坑点实录4.1 坑一编码问题导致的重定向参数被截断这是最典型的失误。当你把stockApi参数的值设为http://合法域名/redirect?pathhttp://192.168.0.12:8080/admin如果你直接把这个 URL 作为参数值发送服务端在解析时可能会把?pathhttp://192.168.0.12:8080/admin这一整段当作stockApi的查询参数。如果你传的又是 POST 表单格式和?会被表单解析器优先处理导致后面的参数变成独立的键值对。解决方案是对整个 URL 做一次 URL 编码或者把内层 URL 里的关键字符?、、全部编码。我自己的习惯是先把替换为%26再把?替换为%3F这样可以百分之百避免表单解析器误判。另外要考虑服务端是否会对 URL 再做一层解码。如果解码次数超过一次你可能需要双重编码。这个判断方法很简单提交后看服务端返回的错误信息。如果它告诉你 URL 格式不对大概率就是编码层数不够或者多了。4.2 坑二过滤器不是按字符串匹配而是按解析后的 URL 匹配很多初学者会去尝试各种“绕过姿势”比如http://127.0.0.1http://2130706433http://0x7f000001http://[::1]但实测后发现这些全部被拦截。原因在于过滤器拿到的不是原始字符串而是经过了标准化的 URL 对象。也就是说它先把你传入的字符串解析成 host、port、path 等组件再对这些组件做校验。你用十进制 IP 还是十六进制 IP在解析后都会被还原成点分十进制格式然后照样被识别。所以正确的思路是放弃字符串层面的绕过转向逻辑层面的绕过——也就是利用开放重定向。当然有时候过滤器只验证了 hostname 是否合法 IP而忽略了重定向后的目标。这种“检查第一步、不检查第二步”的漏洞就是这道题真正考验你的地方。4.3 坑三开放重定向入口被确认了但服务端不跟随跳转有时候你用浏览器或者 Burp 测试开放重定向入口是可以正常跳转的但服务端发起请求后却没有任何反应。可能原因包括服务端用的 HTTP 库默认关闭了自动重定向如某些定制化环境或旧版本的 Java 库。服务端使用了“受限重定向”策略只跟随同域跳转。前者可以通过换成“直接请求内网地址”的方式验证后者则需要寻找一个同域名的跳板或者在同一个域里构造二次跳转链。如果服务端确实不跟随重定向这道题用开放重定向就做不了得换其他思路。但大部分情况下靶场设计者默认服务端跟随了重定向所以卡在这里时优先怀疑自己的参数构造有问题而不是服务端实现有问题。4.4 坑四过度依赖浏览器测试重定向忽略了服务端与浏览器的解析差异浏览器对 URL 的解析宽容度很高遇到不规范的 URL 它也会尽量去补全。但服务端的 URL 解析器通常更严格尤其是在处理//开头的协议相对 URL 时不同语言、不同版本的行为差异很大。比如 Go 的net/url解析器会把//host/path中的host当作 Host 字段而 Python 的urllib.parse.urlparse如果没指定协议有时会把它识别为 path 的一部分。你测试 A 工具得到的结论换一个工具可能完全失效。因此我强烈建议当你怀疑服务端解析逻辑与预期不符时用一个外部 URL 快速验证。具体方法是把path参数设为//your-server.com/path然后在你服务器上部署一个请求记录器或者直接在云函数里打印请求头。观察收到的请求是不是来自目标靶场服务器、请求的路径是什么。这一招能快速判断服务端的解析行为而不用盲目猜。4.5 坑五拿到了管理后台但不知道删除哪个用户有些靶场题目不会明确告诉你删除哪个用户只说了“delete the user carlos”之类。如果你英语不好或者没仔细读题很容易在管理后台误删别的用户导致题目不通过。管理后台的用户列表通常以表格展示包含用户名和操作按钮。你要做的就是把题目里给出的用户名找到然后对那一行执行删除操作。别一股脑全删了——有些靶场对操作次数有限制误删后重置环境又要重新打一遍。5. 防御视角这个漏洞在真实场景中如何防护打完靶场只是第一步更重要的是把思路延伸到真实业务中。你可以把这个攻击链想象成一个多层防线单一防线被突破不致命但多层同时失效就很危险。从防御者的角度看至少有三层需要加固。5.1 加固 SSRF 过滤器的两层检查第一层是入口参数校验对所有服务端发起的请求来源 URL 做白名单校验不允许访问内网 IP 段、回环地址、链路本地地址等敏感网络范围。要注意校验对象必须是 URL 解析后的结果而不是原始字符串。不然十进制 IP、十六进制 IP、Unicode 域名这些就能轻易绕过。第二层是 DNS 重绑定防护因为很多 URL 第一次解析时指向的是合法域名但 DNS 解析结果可能是内网 IP。业界常用的方案是“二次解析校验”——即先用解析器获取 IP发起连接前再校验一次或者在 DNS 解析后锁定 IP防止解析结果变化。这个机制能有效防住针对解析时机差进行的绕过。此外更彻底的做法是在应用层禁止跟随重定向或者在跟随重定向后对目标地址再做一次校验。这意味着第一步请求可以放行到任意外部域名但 302 返回的 Location 如果指向内网直接拦截。这就是针对“开放重定向绕过 SSRF”的精准防御。5.2 开放重定向漏洞本身的修复策略修复开放重定向首先要对所有重定向参数做域名白名单校验。例如redirect参数的目标必须属于本公司域名或授权的第三方域名。校验方式不要用字符串包含比如判断evil.com是否包含.com而是对 URL 做解析后比较 hostname 与白名单列表。其次如果业务上确实需要支持外部跳转建议使用“间接跳转”模式前端提交一个跳转标识后端根据映射表找到真正的目标 URL而不是直接使用用户传入的字符串做跳转。这样即使攻击者拼出了一个恶意 URL服务端也只会查找映射表中的对应记录找不到就拒绝。实测中最容易被忽略的是//开头的协议相对 URL。它不包含明显的域名但会被浏览器解析为当前协议 指定域名。如果校验逻辑只检查“URL 是否以 https:// 开头”就会直接放行//evil.com。防御方必须对这个写法做额外处理。5.3 从这道题延伸出的攻击面思考最后说点题外的。这道题的核心价值不仅仅是教会你一个绕过姿势更重要的是提醒你逻辑漏洞往往比技术漏洞更隐蔽。开放重定向本身可能是“低危”但它与 SSRF 组合后就变成了“高危”SSRF 如果结合了云环境元数据服务还能进一步升级为任意文件读取甚至命令执行。单个漏洞的严重程度不能孤立评估要看它能与哪些其他漏洞串联。在真实渗透测试中我遇到过一个类似的场景某系统提供了一个“URL 截图预览”功能它会抓取传入 URL 的页面内容并生成缩略图。起初防护做得很好直接封死了内网 IP。但后来我发现在某个子域名下存在一个开放重定向于是构造了“截图功能请求这个子域名的重定向链接跳到内部管理系统的图片上传接口”的链路最终拿到了内部系统的日志文件路径。这个案例里每一个环节单独看都是“小问题”组合起来却形成了一个完整的攻击链。这也是为什么我在带新人时会专门强调碰到 SSRF 类型的题目别急着写 payload先在目标应用里找“跳板”。很多时候你已经站在了终点线的后面就差一个合法入口。6. 个人经验这类题目对实战思路的两个长期影响这是我反复刷 SSRF 系列题目之后最明显的一个体会不要只会用字典打天下。很多人在 SSRF 上花了一堆时间结果遇到一个新环境还是一脸懵因为他脑子里只有localhost、127.0.0.1这几个词。真正打开思路的那一刻是你意识到“问题是过滤器而不是地址”的那一刻。后来我在排查一个真实业务系统的漏洞时就沿用了这个思路。系统允许用户提交“商品图片 URL”服务端会去拉取图片做尺寸裁剪。我提交了一个站内跳转链接链接指向某第三方登录接口该接口又支持自定义回调域最后回调目标被指向了云环境的内网元数据地址。每一步都是正常的功能组合但串联起来就是在没有任何硬编码漏洞的情况下拿到了云凭证。这种思路一旦建立起来看到“被过滤”的报错就会下意识地去想“有没有办法让服务端自己去打开那扇门”而不是在原地硬刚过滤规则。靶场训练的价值就在这里——它训练的是思维模式而不仅仅是复制粘贴的 payload。