SSRF漏洞实战:利用Gopher协议与BurpSuite攻击内网服务 1. 项目概述从靶场到实战的SSRF漏洞利用在网络安全的学习和渗透测试实践中SSRFServer-Side Request Forgery服务端请求伪造漏洞一直是一个既经典又充满挑战的议题。它允许攻击者诱使服务器向内部或外部的任意地址发起请求从而绕过防火墙、访问内网服务甚至与数据库、缓存等内部组件进行交互。而Gopher协议这个几乎被现代浏览器遗忘的古老协议在SSRF攻击中却扮演着“瑞士军刀”般的角色它能封装多种协议请求是攻击内网Redis、MySQL、FastCGI等服务的利器。我最初接触SSRF和Gopher协议也是在CTF比赛中。面对一个看似只有简单回显的Web应用如何一步步将其转化为通向内网深层的跳板这个过程充满了“解谜”的乐趣和技术的深度。很多教程止步于理论告诉你“Gopher协议可以攻击内网服务”但具体怎么构造那个关键的Payload如何利用BurpSuite这样的工具进行精确的调试和利用往往语焉不详。这正是本文想要解决的问题我们不谈空泛的概念直接从CTFHub这个优秀的实战靶场出发手把手地带你走通从漏洞发现、协议理解、Payload手工/工具生成到最终利用的完整链条。这篇文章适合有一定Web安全基础了解HTTP协议使用过BurpSuite进行过抓包改包操作的读者。无论你是正在备战CTF的选手还是希望夯实Web渗透实战技能的安服人员我相信这套结合了靶场实战和工具链的“组合拳”能让你对SSRF漏洞的理解和利用能力提升一个实实在在的档次。我们将聚焦于如何让BurpSuite成为你构造Gopher Payload的“神兵”而不仅仅是抓包工具。2. 核心思路拆解为什么是Gopher协议与BurpSuite的组合在深入实战之前我们必须先理清两个核心问题为什么在SSRF利用中Gopher协议如此强大又为什么选择BurpSuite作为主要工具而不是简单的Python脚本2.1 Gopher协议的“降维打击”能力Gopher是一个比HTTP还早的网络协议设计简单其请求格式大致为gopher://host:port/gopher-path后接一个TCP数据流。它的强大之处在于这个gopher-path或者说发送的TCP数据流可以是任何基于TCP的协议命令。服务器在收到SSRF请求后会向指定的host:port建立TCP连接并直接发送我们构造的数据流。这意味着我们实际上是在让受害服务器“代劳”直接与内网中某个服务的TCP端口进行“裸”的协议交互。举个例子内网有一台Redis服务器默认端口6379外部无法直接访问。但如果存在SSRF漏洞我们就可以构造一个符合Redis协议格式的数据流通过Gopher协议让Web服务器发送给内网的Redis。这个数据流可以是一条SET或FLUSHALL命令从而达到数据篡改甚至清空的目的。这种攻击不依赖于HTTP而是直接触及应用层协议的本质因此能绕过很多仅针对HTTP请求的防护规则。2.2 BurpSuite在Payload构造中的不可替代性你可能会想我用Python的socket库也能构造TCP数据流为什么非得用BurpSuite原因在于可视化、可调试和可迭代。首先可视化构造。BurpSuite的Repeater模块允许你随意修改请求的每一个字节并以十六进制Hex视图查看这对于构造包含非打印字符如换行符\r\n、空字节\x00的协议Payload至关重要。在Python脚本里你需要不断调整字符串转义而在BurpSuite里你可以直接点击编辑。其次实时调试与回显。在CTFHub靶场中你构造的Payload发送后服务器的响应无论是错误信息还是成功回显会立刻显示。你可以根据响应快速判断Payload哪里出了问题是命令格式不对还是长度计算错误这种即时反馈的调试循环效率远高于“编写脚本-运行-查看结果-修改脚本”的模式。最后流程化集成。从漏洞探测Scanner Intruder到Payload精细构造Repeater再到最终利用BurpSuite提供了一个无缝的环境。特别是它的Collaborator功能社区版无在真实渗透中用于探测盲SSRF和接收外带数据非常有用。对于Gopher Payload生成我们虽然会用到一些外部转换思想但核心的调试和发送环节都在BurpSuite内完成。我们的核心思路就是以CTFHub靶场为具体目标利用BurpSuite作为核心操作台深入理解Gopher协议封装不同服务请求的原理并掌握手工与半自动化生成有效Payload的方法最终达成SSRF漏洞的深度利用。3. 靶场环境搭建与SSRF漏洞初探工欲善其事必先利其器。在开始炫技之前我们先确保环境就绪并对靶场有一个基本的认识。3.1 工具准备与BurpSuite基础配置你需要准备两样东西BurpSuite Community/Professional版和CTFHub的SSRF技能树靶场。BurpSuite的安装激活过程不再赘述网上教程很多记得配置好浏览器代理通常是127.0.0.1:8080并安装BurpSuite的CA证书以便拦截HTTPS流量。这里重点提几个对后续操作关键的BurpSuite配置和模块Project options - Connections确保支持上游代理如果你需要和DNS解析设置无误。User options - Display建议开启“Show non-printable characters using hex encoding”这样在查看请求时能清晰看到\r\n等字符。核心模块我们会用到Proxy代理拦截、Repeater重放器和Intruder入侵者。Decoder模块也经常用于编解码操作。3.2 CTFHub SSRF靶场结构解析CTFHub的SSRF技能树提供了由浅入深的多个关卡非常适合系统性学习。我们选取其中涉及Gopher协议和内网服务利用的典型关卡作为示例例如“Gopher协议”、“内网访问”、“POST请求”等。每个关卡通常是一个简单的PHP或Python Web应用页面提供一个输入框让你提交一个URL后端会使用file_get_contents()、curl或requests库等去获取这个URL的内容并显示。漏洞点就在于后端程序在获取URL前对用户输入的过滤不完善。常见的过滤包括禁止127.0.0.1、localhost、192.168.*等内网地址。限制协议仅为http://或https://。检查URL中是否包含某些关键词如flag、admin。尝试解析URL的最终IP地址判断是否属于内网段。我们的任务就是利用URL解析差异、过滤器绕过技巧和Gopher协议的强大能力让服务器访问到被禁止的内网资源。靶场的回显机制将请求结果部分或全部显示在页面上为我们提供了宝贵的调试信息。3.3 第一个SSRF探测与基础绕过假设第一个关卡只是简单地禁止了127.0.0.1。你可以尝试以下Payloadhttp://0.0.0.0/在某些环境下0.0.0.0指向本机http://[::]/IPv6的本地地址http://127.0.0.1.nip.io/利用DNS解析nip.io会将127.0.0.1.nip.io解析为127.0.0.1http://2130706433/将127.0.0.1的十进制IP转换http://127.1/短地址形式使用BurpSuite的Repeater你可以快速批量测试这些Payload观察响应变化。如果页面显示了本机Web服务的首页如Apache2 Ubuntu Default Page恭喜你基础SSRF漏洞存在。这个阶段的目标是确认漏洞存在并理解过滤规则为后续更复杂的Gopher利用铺平道路。注意靶场环境是安全的但在真实测试中务必获得书面授权。未经授权的SSRF测试可能对目标业务造成严重影响如攻击内网Redis导致数据丢失。4. Gopher协议深度解析与Payload构造原理现在进入核心环节。要让Gopher协议发挥作用我们必须理解它如何封装数据以及目标服务如Redis的协议格式。4.1 Gopher协议请求格式详解一个标准的Gopher请求看起来是这样gopher://127.0.0.1:6379/_DATA。关键点在于_DATA部分它是要发送的原始TCP数据流。在发送前这个数据流需要经过URL编码因为Gopher路径是URL的一部分。此外有几个特殊规则数据流中的第一个字符会被忽略通常我们用一个下划线_或任意字符占位。数据流必须以\r\n回车换行结尾表示一次Gopher请求的结束。如果需要发送多行数据比如一个HTTP POST请求每一行都要以\r\n结尾。所以构造Gopher Payload的本质就是按照目标协议Redis、MySQL等的格式拼装好完整的命令字节流然后进行URL编码最后拼接在gopher://host:port/_之后。4.2 目标服务协议速览以Redis为例我们以最经典的攻击内网Redis为例。Redis的协议是简单的“文本行”协议称为RESPRedis Serialization Protocol。一条简单的SET key value命令在TCP层面发送的原始数据是*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n解释一下*3表示这是一个有3个元素的数组。\r\n是行分隔符。$3表示下一个元素是长度为3的字符串。SET是命令本身。后续$5和mykey、$7和myvalue同理。如果我们想通过SSRF让服务器在本地Redis上执行这条命令就需要把这个字符串作为_DATA构造出gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aSET%0d%0a$5%0d%0amykey%0d%0a$7%0d%0amyvalue%0d%0a。注意这里的\r\n被URL编码成了%0d%0a。4.3 使用BurpSuite手工构造Gopher Payload完全手写这些编码很麻烦。BurpSuite可以极大地简化这个过程。在Repeater中先随意输入一个http://example.com的请求并发送到靶场。在响应或请求历史中找到你提交URL的那个参数比如url将其值替换为gopher://127.0.0.1:6379/_。现在关键的一步你需要将Redis命令的原始字节流粘贴进去。但直接粘贴*3\r\n...BurpSuite可能会将其作为字面字符串处理。更好的方法是 a. 打开BurpSuite的Decoder模块。 b. 在文本区输入你的原始命令流如*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n。 c. 在“解码为”下拉菜单中选择“URL”。你会看到编码后的结果*3%0d%0a$3%0d%0aSET%0d%0a$5%0d%0amykey%0d%0a$7%0d%0amyvalue%0d%0a。 d. 复制这个编码后的字符串粘贴到Repeater中gopher://.../_的后面。发送请求。如果靶场配置了Redis且漏洞存在你可能会在回显中看到Redis的响应如OK或者触发你想要的动作。实操心得在Repeater的请求体里直接编辑URL编码字符串时BurpSuite有时会自动解码显示。为了确保发送的是原始编码可以切换到“Hex”视图进行编辑和核对。这是避免Payload畸变的关键技巧。5. 实战利用Gopher攻击内网Redis写入WebShell理论说得再多不如一次实战。我们模拟CTFHub中一个典型场景目标存在SSRF内网127.0.0.1:6379运行着Redis并且Web目录已知如/var/www/html。我们的目标是利用Redis将一句话PHP木马写入Web目录。5.1 攻击链梳理与命令构造Redis可以通过CONFIG SET dir和CONFIG SET dbfilename来设置工作目录和数据库文件名。如果Web进程有权限向该目录写文件我们可以将数据库文件设置为.php后缀并在内容中包含PHP代码。攻击链如下连接Redis。设置数据库存储目录为Web根目录CONFIG SET dir /var/www/html设置数据库文件名为WebShell文件CONFIG SET dbfilename shell.php写入一个键值对值包含PHP代码SET payload ?php eval($_POST[cmd]);?执行保存SAVE我们需要将这一系列命令组合成一个连续的TCP数据流。注意Redis是支持管道pipeline的可以将多条命令一次性发送。所以我们的原始数据流将是这5条命令RESP格式的拼接。5.2 使用BurpSuite的Decoder与Repeater协同构造手动拼接5条命令的RESP格式极易出错。我们可以借助一些在线工具或脚本生成基础Payload但用BurpSuite调试更稳妥。这里介绍一种半手工方法先用Python或心算写出每条命令的RESP格式。例如CONFIG SET dir /var/www/html变为*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$3\r\ndir\r\n$15\r\n/var/www/html\r\n解释*4表4个元素CONFIG,SET,dir,/var/www/html。每个元素前有$长度。将5条这样的字符串按顺序拼接成一个长字符串。将这个长字符串粘贴到BurpSuite Decoder的文本区先选择“URL”编码得到编码后的结果。在Repeater中构造请求urlgopher://127.0.0.1:6379/_ [编码后的长字符串]。发送请求。5.3 调试技巧与常见问题排查第一次尝试很可能失败。以下是常见的坑和排查思路问题1无回显或返回错误。排查检查Redis是否真的运行在6379端口。可以先用一个简单的PING命令Payload测试*1\r\n$4\r\nPING\r\n。如果连PING都不通可能是端口不对或网络不通。排查检查Gopher Payload的格式。确保第一个字符是任意字符_确保整个数据流以\r\n结尾。在Hex视图下检查%0d%0a是否正确。排查检查RESP格式。每个数组元素$长度必须严格等于后面字符串的字节数。例如dir是3字节$3必须匹配。中文或特殊字符长度计算容易出错。问题2命令执行了但文件没写入或内容不对。排查权限问题。Web进程可能无权向/var/www/html写入。可以尝试其他已知目录如/tmp。排查Redis配置问题。某些Redis版本以低权限运行或禁用了CONFIG命令。可以尝试用INFO命令查看信息。排查PHP代码被转义或截断。确保在RESP格式中PHP代码字符串的长度计算正确且其中的$符号前没有加转义在RESP里$是协议的一部分但在字符串里就是普通字符。在Hex视图下确认?php ... ?的字节流是否正确。注意事项在实际CTF或渗透中写入WebShell后你需要用蚁剑、菜刀或curl去连接这个Shell。在CTFHub靶场中目标可能是让你读取一个flag文件那么写入的WebShell代码可以是?php echo file_get_contents(/flag);?。6. 扩展攻击面Gopher协议封装其他协议Redis只是Gopher协议的“经典案例”。它的威力在于通用性。我们可以用同样的思路攻击其他内网服务。6.1 攻击FastCGIPHP-FPMFastCGI是PHP与Web服务器如Nginx通信的协议。如果内网存在暴露的PHP-FPM端口如9000且我们知道Web目录就可以通过Gopher发送恶意的FastCGI协议包让PHP-FPM执行任意代码。这比攻击Redis更直接因为直接操作了PHP进程。构造FastCGI的Payload比Redis复杂得多因为它是一个二进制协议需要构造包含PHP_VALUE、PHP_ADMIN_VALUE等环境变量的请求体用于修改PHP配置如auto_prepend_file最终包含恶意代码。通常我们需要借助专门的工具如gopherus来生成Payload但理解其原理后你同样可以在BurpSuite中对生成的Payload进行微调。6.2 攻击MySQL攻击内网MySQL的思路与Redis类似但协议不同。你需要构造MySQL客户端的握手包和查询包。一个常见的攻击链是通过LOAD_FILE()函数读取服务器文件或通过SELECT ... INTO OUTFILE写入文件需要FILE权限和secure_file_priv设置允许。Gopher Payload需要封装完整的MySQL客户端登录和查询过程。由于MySQL协议更复杂手工构造极其困难。实践中通常使用像ysoserial的MySQL客户端模块或特定脚本生成Payload然后将生成的字节流进行URL编码再嵌入Gopher URL。6.3 封装HTTP/HTTPS请求Gopher甚至可以封装完整的HTTP POST请求。这在某些SSRF题目中非常有用例如题目限制只能使用Gopher或Dict协议但你需要向一个内网HTTP接口提交数据。你可以将完整的HTTP请求头和方法体按照一行\\r\\n的格式拼接然后进行Gopher封装。例如一个POST请求POST /api/data HTTP/1.1 Host: internal.service Content-Type: application/x-www-form-urlencoded Content-Length: 9 keyvalue需要转换成gopher://internal.service:80/_POST /api/data HTTP/1.1\r\nHost: internal.service\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 9\r\n\r\nkeyvalue\r\n然后进行URL编码。注意Gopher数据流的第一行第一个\r\n前有特殊含义所以通常用一个无关字符如_开头后面跟\r\n再跟HTTP请求。7. 自动化Payload生成与高级利用技巧手工构造复杂协议的Payload是繁琐且易错的。作为实战派我们需要借助一些自动化工具来提升效率同时掌握一些高级绕过技巧。7.1 利用工具生成Payload基底推荐几个常用的工具它们可以生成针对不同服务的Gopher PayloadGopherus 功能强大支持生成攻击Redis、MySQL、PostgreSQL、FastCGI、Zabbix等的Payload并且集成了写入WebShell、执行命令等多种利用方式。它是命令行工具生成的是编码前的原始命令流方便我们复制到Burpsuite进行二次加工和调试。SSRFmap 一个功能全面的SSRF自动化利用框架内置了字典、多种协议利用模块包括Gopher和盲打功能。它更适合在授权测试中进行全面探测。自己编写Python脚本 对于特定场景或学习协议自己写脚本是最佳选择。你可以用socket库模拟客户端与服务端交互捕获TCP流量然后将其转换为Gopher格式。这能让你对协议有最深刻的理解。使用这些工具时切勿完全依赖黑盒。将工具生成的Payload放入BurpSuite的Decoder和Repeater中分析其结构理解每一部分的作用。这样当下次遇到工具不支持的场景时你才有能力手动调整。7.2 在BurpSuite中集成与调试自动化Payload以Gopherus为例生成一个攻击Redis写入公钥的Payloadpython gopherus.py --exploit redis工具会交互式地询问Redis路径、本地公钥路径等最后输出一大段编码后的字符串。你的操作流程应该是复制工具输出的编码前的原始数据流通常以_开头的一长串字符。将其粘贴到BurpSuite Decoder的文本区。进行URL编码Encode as URL。将编码结果拼接到gopher://host:port/_后面在Repeater中发送。观察响应如果失败利用Hex视图对比工具生成的流和你理解的RESP格式是否有出入进行微调。这个过程将工具的“自动化生成”和BurpSuite的“可视化精细调试”完美结合。7.3 绕过过滤与WAF的高级技巧靶场和真实环境往往存在过滤。除了基础的IP地址绕过针对Gopher和协议本身的过滤也需要应对协议黑名单 如果过滤了gopher://可以尝试大小写混淆Gopher://、GOPHER://或者利用URL解析特性如gopher://被过滤是否可以尝试gopher:不完整或其他罕见协议如dict://功能较弱作为替代。端口限制 限制只能访问80443等端口。如果内网服务运行在非标准端口此路不通。但可以考虑端口重定向或利用Web应用本身的反向代理功能如果存在。请求长度限制 复杂的Gopher Payload可能很长。可以尝试拆分攻击链分多次请求完成。例如第一次SSRF设置Redis目录第二次再写入文件。DNS重绑定攻击 这是应对IP黑名单的终极技巧之一。你控制一个域名其DNS记录TTL极短第一次解析返回一个允许的外网IP通过校验第二次解析时你迅速将其改为127.0.0.1。服务器在获取URL内容时进行第二次解析就会访问到内网地址。这需要你拥有一个域名并配置特殊的DNS服务。8. 防御视角与总结反思在精通攻击之后从防御者角度思考能让你对漏洞的理解更加立体。如何防御SSRF特别是防范Gopher协议的攻击输入验证与白名单 最有效的方法。严格校验用户输入的URL不仅检查域名/IP是否在内网段更应建立允许访问的协议白名单通常只允许HTTP/HTTPS和目标地址白名单。使用解析后的IP进行判断而非字符串匹配。禁用危险协议 在服务器端禁用不必要的URL包装器Wrapper。在PHP中可以通过allow_url_fopen和allow_url_include进行控制更精细地是在php.ini中禁用gopher://、dict://、file://等协议。网络层隔离 确保承载Web应用的服务器可能产生SSRF与重要的内网服务Redis、MySQL、Consul等处于不同的网络分区通过防火墙严格限制访问。即使存在SSRF攻击者也触及不到核心资产。服务加固 为内网服务设置认证密码如Redis的requirepass绑定监听IP127.0.0.1而非0.0.0.0使用非默认端口。这能大幅增加利用难度。输出过滤 对服务器获取的外部资源内容进行过滤或限制回显避免敏感信息泄露增加盲SSRF的利用难度。回过头看从CTFHub靶场的一次次尝试、失败、调试到成功整个过程是对耐心和技术的双重磨练。BurpSuite不仅是抓包工具更是你手工Payload的“锻造炉”和“试金石”。Gopher协议则像一把钥匙打开了SSRF通往内网深处的一扇门。掌握这套技术意味着你在Web渗透的深度上又前进了一大步。真正的熟练不在于记住多少个Payload而在于理解了“协议封装”这一核心思想并能举一反三。下次遇到SSRF你的思路会更清晰先探测过滤规则再根据内网服务情况选择合适的协议Gopher/Dict/HTTP最后用BurpSuite精细构造和调试Payload。安全之路道阻且长但每一步扎实的实战都会让你走得更稳更远。