ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SSRF漏洞详解:从原理、绕过到内网渗透与修复实战

SSRF漏洞详解:从原理、绕过到内网渗透与修复实战 先声明一句我在安全测试这条路上认识SSRF有几年了真正让我重视它的是某次授权渗透里一个看似不起眼的URL输入框直接让我拿到了内网一台数据库的血拼权限。SSRF全称是Server-Side Request Forgery服务端请求伪造它利用的是服务器端的URL解析缺陷让服务端自己发起恶意请求。很多开发朋友觉得它只是个HTTP请求转发实际上它的杀伤范围覆盖内网探测、云元数据窃取、Redis等内网服务利用甚至能联动RCE。这篇内容写给三类人刚入门的安全同学想搞懂原理和利用逻辑开发同学想弄清楚为什么自己写的代码会中招以及做企业防护的运维想知道怎么彻底堵住这个洞。我会从原理、攻击面、利用链路、绕过手法、修复方案和实战复盘几个维度展开尽量还原我在真实项目中的排查思路。1. SSRF漏洞的成因服务器为什么会帮你请求任意地址1.1 从服务器替你访问的常见业务说起你先忘记技术名词想一个最普通的场景你的产品做了一个文章封面抓图功能用户提交一个图片URL后端PHP用file_get_contents($url)抓取这张图存到本地。这个流程里服务器收到URL之后自己发起了HTTP请求绕过了浏览器的同源策略服务器成了HTTP客户端。问题来了你怎么限制这个URL指向哪里现实是很多代码只判断了URL是否以http/https开头、扩展名是否为jpg/png/gif然后就把请求发出去了。于是用户可以提交http://127.0.0.1:3306、http://169.254.169.254/latest/meta-data/、http://192.168.1.100:8080服务器都会照单全收。这就是SSRF最基本的形态用户传入URL后端发起请求且请求的目标不受严格白名单约束。1.2 哪些代码写法最容易踩中这个雷从代码审计角度看SSRF的高发函数都有一个共同特征接收外部输入作为URL参数然后交给HTTP客户端库或系统命令去执行。例如PHP里的file_get_contents、curl_exec、fsockopenJava里的HttpClient、URLConnection、OkHttpPython里的requests、urllibNode.js里的axios、http.request。这些函数本身没问题但开发者往往忽略了用户输入与请求目标之间的信任边界。我见过一个典型的Java案例业务系统需要访问用户填写的合作方API地址做回调验证代码直接把参数传给HttpURLConnection。测试时一切正常但没有任何人想过用户会填内网地址。直到某天安全团队做内网扫描发现这台web服务器能访问云环境的元数据接口才意识到它其实已经成了内网跳板。凡是业务逻辑里有代理用户指定的URL、抓取远程资源、根据URL生成二维码/PDF这类需求都要默认它是SSRF候选。1.3 判断SSRF的关键标志请求从服务器发出很多人混淆SSRF和其他漏洞关键点就在请求发出者是谁。XSS是浏览器发请求CSRF是受害者浏览器发请求而SSRF是服务器端发请求。在Burp Suite里如果提交一个URL后你看到HTTP历史里多了一条来自服务器的请求记录可以用collaborator或自己的日志服务器观察并且这条请求的目标可以被你控制那基本就是SSRF。验证时有个小技巧把URL指向你自己可控的域名比如notify.dnslog.cn这类DNSLog服务或者自己的VPS然后观察是否收到来自目标服务器IP的解析请求。如果收到了说明目标服务器确实出网了如果目标地址填的是内网段则说明它正在帮你探测内网。这一条验证逻辑贯穿整个利用流程后面我会反复提到。2. 攻击面盘点这些业务场景是SSRF的高产区2.1 图片处理、截图服务与文档转换图片相关功能是SSRF重灾区原因很简单图片本身是远程URL资源产品天然需要服务端去拉取。比如用户头像上传时支持从URL导入、网页版文章编辑器支持粘贴图片外链下载、以及最常见的网页快照截图服务用户输入一个网址服务器用无头浏览器打开后截图。后者更危险因为截图服务往往使用完整浏览器内核不仅能发HTTP请求还能执行JSSSRF可能演变成内网浏览器攻击。文档转换也是典型场景把PDF转换为图片、把HTML渲染成PDF、Office文件在线预览许多转换库如wkhtmltopdf、LibreOffice在解析文档时会主动获取文档里引用的外部资源包括内网地址。我在一次测试中遇到一个在线简历转PDF功能简历里嵌了img标签指向http://127.0.0.1:6379转PDF时服务器对本地Redis端口发起了连接虽然没拿到数据但通过延迟差异能确认端口开放。这就是SSRF不必回显借助时间盲打也能探测内网。2.2 代理与转发型API某些后端接口设计为网关代理形式前端传一个完整URL后端统一代理请求用于解决跨域、隐藏真实API地址或聚合内容例如rss代理oembed解析链接嗅探/外链检查安全服务。这类接口几乎就是SSRF的标配因为它的核心逻辑就是替用户请求任意URL。外链检查服务尤其讽刺明明是安全功能却常常因为只校验了协议头就放过内网地址反而成为最直接的内网探测口。2.3 云环境下的额外杀手锏元数据服务如果你测试的应用跑在阿里云、腾讯云或AWS上SSRF的价值会被放大一个量级。云厂商通常提供http://169.254.169.254/latest/meta-data/这种链路本地地址目标服务器通过它获取自身实例ID、IAM临时凭证、用户数据等敏感信息。攻击者利用SSRF访问这个地址就能拿到云API的临时密钥进而直接操作云资源比如读写OSS存储、创建虚拟机、删除数据库快照影响面从一台内网服务器扩张到整个云账号权限。需要强调一下云元数据接口在公网不可达只有服务器自身的链路本地可以访问所以它是天然的SSRF利用对象。所有部署在云上的应用SSRF风险等级都应该默认调高。我在写修复方案时从来不对云场景做低危误判就是因为这个链路太长。3. 从探测到内网漫游SSRF利用的完整链路拆解3.1 第一步确认参数点能控制完整URL拿到一个疑似SSRF功能先看它接受什么形式的输入。有的接口支持完整URL有的会把域名槽位单独拆出来拼接实际测试方式完全不同。完整URL场景最理想直接替换为攻击者控制的目标即可如果服务端强制补充了一个前缀或路径需要先摸清楚拼接规则才能判断能否通过#、?、等字符做语法层面的逃逸。这里有一个重要经验先区分直接回显SSRF和盲SSRF。直接回显指响应里包含请求结果比如图片抓取功能把远程图片内容返回给浏览器盲SSRF指响应看不到目标内容只能通过状态码差异、响应时间差异、DNSLog回连等间接信号判断。后者在利用时更需要想象力很多内网服务数据未必能原样返回但配合错误信息一样能拿到版本号等指纹信息。3.2 第二步绕过的本质是你以为限制住了其实没有开发者常用的防护是检测URL主机名是否内网IP、是否localhost、域名后缀是否合法但绕过手法层出不穷。整个攻防博弈的核心是开发者的校验只能基于字符串或者一次DNS解析而真实请求发生时会经历多次DNS解析、重定向、URL规范化校验时看到的东西和实际请求的东西可以完全不一样。举例来说校验代码检查host不能是127.0.0.1时完全基于字符串。但黑客提交http://127.0.0.1.nip.io:8080这是*nip.io的域名解析服务会把这个域名解析到127.0.0.1或者用十进制IP表示http://2130706433/都能绕过基于点分十进制的字符检查。绕过不是魔法只是找到校验与实际行为不一致的地方这一点我会在下一章详细展开。3.3 第三步内网信息收集的三板斧确认SSRF可控后内网渗透往往从这里提速。第一板斧是端口存活探测。将URL指向内网IP的特定端口通过响应内容、响应时间或错误类型判断端口是否开放。比如http://192.168.1.10:22SSRF返回SSH的banner或连接超时就能判断22端口开启http://192.168.1.10:3306如果被数据库拒绝错误详情往往能暴露MySQL版本。第二板斧是访问云元数据与敏感管理端口。除169.254.169.254外内网常见的服务如Redis6379、Elasticsearch9200、Docker API2375、Kubernetes API6443、Hadoop YARN8088都是高价值目标。某些协议配合请求方法的差异还能利用SSRF去操作这些服务比如Gopher协议可以构造完整Redis协议包实现写Webshell或反弹Shell这已经不是单纯的HTTP探测而是服务交互层的攻击了。第三板斧是利用重定向扩大攻击面。不管后端限制多么严格只要一个外部URL能302跳转到内网地址很多只关心第一次请求的防护就会失效。我会提供一个可靠建议测试时先找目标服务器上是否有自己的重定向器比如开放的跳转接口如果没有可以用自己VPS上写一个302重定向服务同样能达到绕过目的。4. 防绕过清单我在项目和实战中总结的修复与校验方案4.1 常见绕过方式汇总安全测试人员的价值在于把攻击者手法透明化。我按解析层网络层协议层梳理了绕过方式方便对应修复。绕过类别典型手法实际效果字符串黑名单用十进制/八进制IP如http://2130706433/绕过127.0.0.1的字符串匹配DNS解析差异使用解析到内网的外部域名如*.nip.io、sslip.io绕过IP黑名单但DNS最终指向内网URL规范化利用符号如http://admin127.0.0.1使校验函数识别错主机名重定向URL先访问外网可控服务302跳到内网绕过只检查首个请求的限制协议扩展file:///etc/passwd、gopher://内网Redis从HTTP探测升级为任意文件读取/服务交互回到修复视角你不可能在代码里写死所有恶意花样思路要从防特征转向做边界。4.2 自顶上而下的防护措施业界公认的修复函数是白名单网络层隔离双层防线单靠其中一层都不够。白名单方面如果业务确实需要用户指定URL至少遵循三个限制协议只允许http/https域名必须属于业务允许的域名集合且是精确匹配、不允许子域泛匹配端口限定在80/443如果不是云场景且业务不需要内网访问则绝不放开自定义端口。但白名单本身有坑假如业务允许用户提交任意网站的图片链接那域名集无法固定就必须靠第二层——网络边界。在服务器上通过防火墙/安全组限制出口流量只允许访问公网必要的IP段并禁止访问本机回环地址、链路本地地址169.254.0.0/16、保留内网段 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。这是我认为最有效的兜底方案即使应用层校验被绕过攻击者也无法访问内网IP。DNS校验也应当做加固不能只做一次域名解析就放过因为存在DNS rebinding攻击第一次解析为公网IP第二次解析指向内网IP两次解析结果不一样。可靠的解法是用现有的SSRF防护SDK或自己实现解析校验后携带解析IP连接的机制确保连接使用的IP就是校验通过的IP。4.3 云元数据接口的专项防御在云环境优先级还要加一条禁用或关闭实例元数据服务或者为元数据服务加访问限制。例如某些云服务商支持通过metadata token来访问元数据普通HTTP请求无法直接拉取如果业务不需要使用元数据直接在系统层面封禁169.254.169.254的访问。另外如果有业务必须访问该地址一定要把它加入请求代理的全局拒绝列表因为DNS解析、重定向都可能把这个地址重新引到请求流程里。我在实际修复时会特别检查代码里的重定向跟随设置。很多HTTP库默认跟随重定向即使第一次请求访问的是安全域名第二次也可能跳到内网地址。建议将重定向跟随设为手动并在每次跳转时重新执行白名单校验不能信任第一次安全就永远安全。5. 一块靶场日志还原SSRF从识别到利用的完整记录为了让大家直观感受利用链路我基于自己练习用的CTF靶场环境做一个复盘目标站点是一个内网的网页截图API接口为/api/shot?url。5.1 第一步确认回显型SSRF向接口提交urlhttps://example.com返回的是截图文件的地址说明服务端会真实访问该URL并将渲染结果保存到本地回显型SSRF确认。接着提交urlhttp://127.0.0.1:8080返回内容里出现了Tomcat默认错误页说明服务端确实尝试访问了本地8080端口并且把错误信息带回了响应。此时基础能力已经齐了能访问内网、有回显、支持任意HTTP端口探测。5.2 第二步利用重定向绕过域名白名单靶场其实限制了url参数首段必须是http(s)://且不能是localhost。于是我在自己VPS上配置一个302跳转跳转地址指向联系方式中的内网地址http://10.0.0.11:7001。提交urlhttp://我的VPS/redirect?tohttp://10.0.0.11:7001后截图结果展示了WebLogic管理后台的登录页。这再次验证了上面强调的重定向可绕过只查首跳的校验这种绕过在真实应用里太常见了。5.3 第三步从HTTP探测转向内网指纹利用跳转URL逐个探测内网常见端口我拿到了这些开放端口10.0.0.11的7001WebLogic、10.0.0.12的6379Redis且用gopher协议验证不需要密码、10.0.0.13的9200Elasticsearch。Redis这个问题在真实测试中非常致命——如果允许SSRF发起Gopher协议请求可以构造Redis写计划任务或写公钥直接RCE。虽然靶场环境没有继续深入但整个利用链已经从网页截图功能扩展到了未授权访问Redis危害一目了然。5.4 修复对照复盘后我给这个靶场的防护建议是截图服务必须改用固定内网代理池且代理池只能访问白名单公网域名对出网流量实施VPC网络ACL封锁禁止访问保留地址段gopher协议在应用层直接禁用HTTP客户端只允许http/https重定向跟随必须手动校验每一次跳转。这套组合在任何环境都值得复制。6. 开发与测试同学的协作视角SSRF修复不是安全部门一家的事SSRF经常被当作开发随便修一下的问题但真实修复难点在于业务形态各异。比如用户提交任意URL生成二维码这种需求你很难用域名白名单约束因为用户本来就可以提交任意网址。这时最务实的方案是让请求走一个专用的只读请求代理这个代理自身不持有内网访问权限并且对响应做严格的内容白名单再把返回内容过滤掉内网IP、错误堆栈等敏感信息然后把代理地址和原始SSRF地址保持隔离。开发同学看到限制访问内网的第一反应常常是那我的服务怎么调内网其他组件的API这就需要分清业务内部访问和用户可控URL发起的访问内部组件访问走配置中心的服务发现不依赖用户输入的URL用户可控URL的请求一律走独立出口两个流量面的权限边界必须分开。我在推动修复时会建议开发给用户可控请求单独建一个出口代理而不是在业务主逻辑里简单加个判断这个边界一旦建立后续很多同类漏洞都能被自动隔离。代码层面也应该统一封装一个SafeHttpClient工具类把DNS解析校验、端口白名单、重定向跟随限制、响应敏感信息过滤全部收敛到一个地方而不是在每个调用curl、requests的地方零散过滤。我见过太多因为只在一个接口修了其他接口忘了导致的SSRF复发。统一封装并配上单元测试专门构造绕过案例做执行这类问题才能从根上减少。7. 测试工程的优先排序漏洞挖掘中别漏掉这三个易忽略点7.1 不要忽略盲SSRF下的时间探测盲SSRF没有回显时许多测试人员会直接跳过其实时间盲探测一样有效。提交urlhttp://10.0.0.1:8080如果目标端口开放请求会快速失败或建立连接如果端口关闭连接超时要等很久。把同一地址的开放端口和关闭端口的响应时间做成基线可以靠延时差判断端口状态。更细的还可以对目标网段的多个IP做扫描代价低且隐蔽。7.2 非HTTP协议可能比HTTP更危险多数SSRF测试默认只有http/https但代码若使用了支持任意协议的库如curl支持Gopher、Dict、FTP攻击面完全不同。利用file协议读本地文件是最直接的验证方式Gopher协议虽然构造起来复杂但对Redis这类基于TCP明文协议的服务几乎为所欲为可以直接写入恶意请求。所以测试时不要只试HTTP多试几个协议看到响应变化再判断支持范围。7.3 二次跳转与无限重定向任何URL参数后接拼接的场景都可能通过#、?等控制实际请求路径。比如代码写了http://www.safe.com/{input}你可以提交../../secret试试路径穿越代码写了http://api.example.com/?url{input}你提交127.0.0.1试试凭证混淆。同时注意服务端可能自行拼接路径导致即使域名无法绕过路径部分仍然可以精准指向内网服务的特定端点。8. 常见问题快答问SSRF修复中过滤百度增加了127.0.0.1、localhost、127.x.x.x是否就够了 答不够。只能过滤常见的字面量十进制IP、DNS重绑定、重定向、URL编码都能绕过必须配合DNS解析校验和出口ACL。问为什么我做的网站只在浏览器里允许访问后端依然有SSRF 答SSRF本质是服务端发请求用户是否在浏览器能直接访问完全不重要。只要后端接受用户可影响的传入URL攻击者可以完全绕开浏览器直接发HTTP请求给后端接口。问Gopher协议为什么危险 答Gopher能把一串原始TCP数据写进请求里这意味着可以手动构造Redis协议、MySQL协议等不只是发个HTTP GET那么简单可以直接与服务交互。修复时最好在HTTP客户端层直接禁用非http/https协议。问SSRF能盈利吗我听说有人靠挖SRC拿了几万奖金。 答在漏洞挖掘授权范围内能。云环境上的SSRF常被定级为高危甚至严重因为它能触碰元数据凭证内网穿透型SSRF也常被评为中高危。但我必须强调只允许在授权范围内测试任何未授权扫描都涉嫌违法不存在赚快钱免罪的说法。处理SSRF这么多年我最大的体会是它不像SQL注入那样一条语句打天下而是非常依赖攻击面理解和上下文组合同一个SSRF在图片剪辑型应用、文档编辑型应用、云上网关型应用中的威胁等级完全不同。真正防住它靠的不是某个函数写得多严谨而是从一开始就尊重用户输入不可信任这个底线把请求边界制度化、统一化。希望这篇内容能帮你在下一次代码分析或渗透测试中少走几步弯路尤其是那些容易让请求悄悄穿过内网的隐蔽坑早点发现、早点堵上。
返回列表