gopher协议的利用

近期看到了很多大佬的面经,都问到了gopher扩展攻击面的知识,之前使用gopher利用过ssrf漏洞,但也仅仅停留在会用,并不是很了解,(今天挂着网课来总结一下),也算是逃课专业户了。

什么是gopher协议

gopher协议是一个古老且强大的协议,可以理解为是http协议的前身,他可以实现多个数据包整合发送。通过gopher协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。

很多时候在SSRF下,我们无法通过HTTP协议来传递POST数据,这时候就需要用到gopher协议来发起POST请求了。

gopher的协议格式如下:

1
2
3
gopher://<host>:<port>/<gopher-path>_<TCP数据流>
<port>默认为70
发起多条请求每条要用回车换行去隔开使用%0d%0a隔开,如果多个参数,参数之间的&也需要进行URL编码

但是gopher协议在各个语言中是有使用限制的。

语言 支持情况
PHP –wite-curlwrappers且php版本至少为5.3
Java 小于JDK1.7
Curl 低版本不支持
Perl 支持
ASP.NET 小于版本3

gopher发送请求

curl

为了熟悉下gopher,我本机curl发送一下gopher请求到 我的虚拟机。

最后虚拟机启动nc监听来接收一下消息。

查看下curl版本,看看支不支持gopher协议

image-20220628095635651

image-20220628095954171

gopher协议传递HTTP的GET请求

gopher在发送请求时候,必须进行URL编码

我本地准备PHP代码如下

1
2
3
<?php
echo $_GET['name'];
?>

http访问并抓包

image-20220628110059311

get型的http数据包如下

1
2
GET /testg.php?name=xxx HTTP/1.1
Host: 10.211.55.2

直接在Burpsuite 中将数据进行编码(比较方便)

编码的时候在最后一定要补%0d%0a代表结束。

image-20220628110747138

Burpsuite编码后

1
%47%45%54%20%2f%74%65%73%74%67%2e%70%68%70%3f%6e%61%6d%65%3d%78%78%78%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32

结尾没有%0d%0a我们手动添加一下。

转换为gopher

1
curl gopher://10.211.55.2:80/_%47%45%54%20%2f%74%65%73%74%67%2e%70%68%70%3f%6e%61%6d%65%3d%78%78%78%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32%0d%0a

image-20220628112013795

gopher协议传递HTTP的POST请求

修改本地代码如下

1
2
3
<?php
echo $_POST['name'];
?>

我们用gopher协议传递POST请求时,必须要包含这四个,还有一个post传参。

image-20220628114546001

转换为gopher

1
curl gopher://10.211.55.2:80/_%50%4f%53%54%20%2f%74%65%73%74%67%2e%70%68%70%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32%0d%0a%43%6f%6e%74%65%6e%74%2d%54%79%70%65%3a%20%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%2d%77%77%77%2d%66%6f%72%6d%2d%75%72%6c%65%6e%63%6f%64%65%64%0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%38%0d%0a%0d%0a%6e%61%6d%65%3d%78%78%78%0d%0a

image-20220628135138210

关于gopher协议的SSRF攻击

这里找了一道ctfshow上面的题目,在有SSRF漏洞的场景下,利用gopher解题。

打开无密码的MySQL

image-20220628135851574

关于MySQL无密码

https://paper.seebug.org/510/

MySQL客户端连接并登录服务器时存在两种情况:需要密码认证以及无需密码认证。当需要密码认证时使用挑战应答模式,服务器先发送salt然后客户端使用salt加密密码然后验证;当无需密码认证时直接发送TCP/IP数据包即可。所以在非交互模式下登录并操作MySQL只能在无需密码认证,未授权情况下进行,本文利用SSRF漏洞攻击MySQL也是在其未授权情况下进行的。

先说一下解题的过程。

一般 SSRF 打内网应用主要还是通过协议,比如用的比较多的是 gopher

无论是用 gopher 攻击 redis、mysql、还是 ftp,这些主要都是基于 tcp 协议为主。这和 gopher 协议的基本格式有关我们前面也提到了

想要打 MySQL 就需要知道 MySQL 通信时的 TCP 数据流,才能知道要怎么和 MySQL 通信,这里可以通过 Wireshark 抓包来分析。我们后面说。

https://github.com/tarunkant/Gopherus

直接用这个工具,他包含常见的应用 gopher 数据包的格式构造, 原理也是通过 Wireshark 抓包分析,然后写脚本。

img

这串payload粘贴到returl参数下面,生成的 POC 里,_ 字符后面的内容还要 进行url编码。因为 PHP接收到POST或GET请求数据,自解码一次。

img

img

接下来就是找flag的位置了。

img

img

wireshark抓取3306原始数据包

接下来在本地抓包,还原一下这个工具的原理。

抓包与MySQL通信时的TCP数据流,我们本地新建一个MySQL用户并且无密码

1
2
3
CREATE USER 'Sch0lar'@'localhost';
GRANT USAGE ON *.* TO 'Sch0lar'@'localhost';
GRANT ALL ON *.* TO 'Sch0lar'@'localhost';

接下来使用tcpdump来监听抓取3306认证的原始数据包:

1
2
# lo 回环接口网卡 -w 报错 pcapng 数据包
tcpdump -i lo port 3306 -w mysql.pcapng

紧接着本地连接一下MySQL来测试一下命令

然后中止 tcpdump 使用 Wireshark 打开 mysql.pcapng 数据包,追踪 TCP 流 然后过滤出发给 3306 的数据:

image-20220630112408050

抓包这里有一个坑 我这边正常情况wireshrak抓不到包,查了一阵子资料发现,可能是默认使用了SSL安全链接模式才导致我们无法抓包,

--ssl-mode=disabled表示禁用SSL安全连接模式

再次链接抓包。

(看了国光大佬的博客,和其他大佬的博客他们并没有加--ssl-mode=disabled,就能抓到包)猜测原因可能是MySQL版本的问题 可能高版本默认就会采用SSL安全模式进行连接。

image-20220630113159381

保存为原始数据,并生成gopher数据流

image-20220630113308193

生成gopher数据流,采用如下脚本

1
2
3
4
5
6
7
8
9
import sys

def results(s):
a=[s[i:i+2] for i in range(0,len(s),2)]
return "curl gopher://127.0.0.1:3306/_%"+"%".join(a)

if __name__=="__main__":
s=sys.argv[1]
print(results(s))

image-20220630154715976

大致就是这么一个流程。