285 lines
13 KiB
Markdown
285 lines
13 KiB
Markdown
# SSRF Exploitation Evidence
|
|
|
|
## Executive Summary
|
|
|
|
This report documents the comprehensive exploitation testing of one Server-Side Request Forgery (SSRF) vulnerability candidate identified during the analysis phase. After exhaustive testing and verification, the finding has been reclassified as a **FALSE POSITIVE** for SSRF vulnerability.
|
|
|
|
**Key Finding:** The OAuth Dynamic Client Registration vulnerability (SSRF-VULN-01) was initially classified as SSRF but is actually an **Open Redirect vulnerability**. The server does not make outbound HTTP requests to attacker-controlled destinations; instead, it redirects the client's browser using HTTP 303 status codes. This does not meet the definition of Server-Side Request Forgery.
|
|
|
|
**Exploitation Status:**
|
|
- Successfully Exploited: 0
|
|
- Potential Vulnerabilities: 0
|
|
- False Positives: 1
|
|
|
|
## Successfully Exploited Vulnerabilities
|
|
|
|
*No SSRF vulnerabilities were successfully exploited.*
|
|
|
|
## Potential Vulnerabilities (Validation Blocked)
|
|
|
|
*No potential SSRF vulnerabilities requiring further investigation.*
|
|
|
|
## False Positive Analysis
|
|
|
|
### SSRF-VULN-01: OAuth Dynamic Client Registration - Open Redirect (NOT SSRF)
|
|
|
|
**Summary:**
|
|
- **Vulnerable location:** POST /register (unauthenticated), GET /oauth/authorize (authenticated)
|
|
- **Initial Classification:** Server-Side Request Forgery (SSRF) with internal service access capability
|
|
- **Corrected Classification:** Open Redirect vulnerability
|
|
- **Reason for Reclassification:** The server uses `http.Redirect()` which sends an HTTP 303 response to the client's browser, not a server-side HTTP request to the target URL
|
|
- **SSRF Criteria:** ❌ FAILED - Server does not make outbound HTTP requests to attacker-controlled destinations
|
|
|
|
**Detailed Analysis:**
|
|
|
|
The vulnerability allows unauthenticated attackers to register OAuth clients with arbitrary redirect URIs, including internal network addresses. However, the exploitation mechanism does not match the definition of SSRF:
|
|
|
|
**What Actually Happens:**
|
|
1. Attacker registers OAuth client with malicious redirect_uri (e.g., `http://169.254.169.254/latest/meta-data/`)
|
|
2. Attacker (or victim) initiates OAuth authorization flow
|
|
3. Server generates authorization code
|
|
4. **Server sends HTTP 303 redirect response to the CLIENT'S BROWSER**
|
|
5. Client's browser attempts to navigate to the internal URL (and fails from external network)
|
|
|
|
**What Does NOT Happen (SSRF behavior):**
|
|
- ❌ Server does not make HTTP requests to the redirect_uri
|
|
- ❌ Server does not establish connections to internal services
|
|
- ❌ Server does not access internal network resources
|
|
- ❌ Server does not leak internal service responses back to the attacker
|
|
|
|
**Code Evidence:**
|
|
|
|
File: `/repos/inou-portal/portal/oauth.go:139`
|
|
```go
|
|
http.Redirect(w, r, redirectURL.String(), http.StatusSeeOther)
|
|
```
|
|
|
|
This function sends an HTTP 303 status code with a `Location` header - it does NOT make an outbound request. The Go documentation confirms:
|
|
|
|
> "Redirect replies to the request with a redirect to url, which may be a path relative to the request path. The provided code should be in the 3xx range and is usually StatusMovedPermanently, StatusFound or StatusSeeOther."
|
|
|
|
**Exploitation Attempts:**
|
|
|
|
#### Attempt 1: Register OAuth Client with AWS Metadata Endpoint
|
|
|
|
**Objective:** Force server to access AWS EC2 instance metadata service
|
|
|
|
**Method:**
|
|
```http
|
|
POST /register HTTP/1.1
|
|
Host: inou.com
|
|
Content-Type: application/json
|
|
|
|
```
|
|
|
|
**Result:**
|
|
```json
|
|
HTTP/1.1 201 Created
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"client_id": "243f06b1598fb12d49c862ba047b9d1e",
|
|
"client_secret": "b3cec86e5fdf34ddde72a35d945eddb57ec6a985d2dc808e55c42420032cee3f",
|
|
"redirect_uris": [
|
|
"http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
|
],
|
|
"grant_types": ["authorization_code", "refresh_token"],
|
|
"response_types": ["code"],
|
|
"token_endpoint_auth_method": "client_secret_post"
|
|
}
|
|
```
|
|
|
|
**Outcome:** ✅ Client registration successful - No validation of redirect_uri against internal IP ranges
|
|
|
|
---
|
|
|
|
#### Attempt 2: Trigger OAuth Authorization Flow
|
|
|
|
**Objective:** Force server to make HTTP request to AWS metadata endpoint
|
|
|
|
**Prerequisites:**
|
|
- Valid user session (obtained via passwordless authentication with backdoor code 250365)
|
|
- Registered malicious OAuth client from Attempt 1
|
|
|
|
**Method:**
|
|
```http
|
|
GET /oauth/authorize?client_id=243f06b1598fb12d49c862ba047b9d1e&redirect_uri=http%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials%2F&response_type=code&state=test HTTP/1.1
|
|
Host: inou.com
|
|
Cookie: login=6a484f3f85735a03
|
|
```
|
|
|
|
**Server Response:**
|
|
```http
|
|
HTTP/1.1 303 See Other
|
|
Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/?code=4f4f3e67fcf804ce05487c18fdaee6f5b354ecb467f834d9747285369a4b31d7&state=test
|
|
Content-Type: text/html; charset=utf-8
|
|
Content-Length: 177
|
|
```
|
|
|
|
**Analysis:**
|
|
- Server returned HTTP 303 redirect (client-side redirect)
|
|
- **Server did NOT make an HTTP request to 169.254.169.254**
|
|
- Server did NOT receive or return data from the metadata service
|
|
- Browser attempted to navigate to the internal URL (network error from client side)
|
|
|
|
**Outcome:** ❌ NOT SSRF - This is an Open Redirect vulnerability, not server-side request forgery
|
|
|
|
---
|
|
|
|
#### Attempt 3: Register Additional Clients for Internal Services
|
|
|
|
**Objective:** Test if different internal targets yield server-side requests
|
|
|
|
**Targets Tested:**
|
|
1. **Internal API Server:** `http://127.0.0.1:8082/api/access`
|
|
- Client ID: 9863b518919c5c11532b2775e81a0b82
|
|
- Registration: ✅ Successful
|
|
|
|
2. **Signal RPC Service:** `http://192.168.1.16:8080/api/v1/rpc`
|
|
- Client ID: 96478c7a51bc4447f2a54cf6c30ae970
|
|
- Registration: ✅ Successful
|
|
|
|
3. **DICOM Viewer:** `http://localhost:8765/viewer`
|
|
- Client ID: afb78106315871695217d878f6c8b6b9
|
|
- Registration: ✅ Successful
|
|
|
|
**Result:** All clients successfully registered with internal network targets, confirming complete lack of redirect URI validation. However, all subsequent authorization flows resulted in the same behavior: HTTP 303 client-side redirects, not server-side HTTP requests.
|
|
|
|
**Outcome:** ❌ NOT SSRF - Consistent client-side redirect behavior across all internal targets
|
|
|
|
---
|
|
|
|
#### Attempt 4: Search for Alternative SSRF Sinks
|
|
|
|
**Objective:** Identify any code paths where the server actually makes outbound HTTP requests with user-controlled URLs
|
|
|
|
**Code Review Findings:**
|
|
|
|
1. **Google Gemini API Integration** (`/repos/inou-portal/lib/llm.go:109`)
|
|
- URL construction: `fmt.Sprintf("https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent?key=%s", *config.Model, GeminiKey)`
|
|
- User control: ❌ NONE - Model parameter never populated from user input
|
|
- Verdict: Not exploitable
|
|
|
|
2. **Signal Messaging RPC** (`/repos/inou-portal/lib/signal.go:10`)
|
|
- Endpoint: `const signalAPI = "http://192.168.1.16:8080/api/v1/rpc"`
|
|
- User control: ❌ NONE - Hardcoded destination
|
|
- Verdict: Not exploitable
|
|
|
|
3. **Internal API Proxy** (`/repos/inou-portal/portal/api_proxy.go:22`)
|
|
- Endpoint: `const apiBackend = "http://127.0.0.1:8082"`
|
|
- User control: ❌ NONE - Hardcoded destination
|
|
- Verdict: Not exploitable
|
|
|
|
4. **SMTP Email Delivery** (`/repos/inou-portal/lib/email.go`)
|
|
- Configuration: Loaded from environment file
|
|
- User control: ❌ NONE - Administrative configuration only
|
|
- Verdict: Not exploitable
|
|
|
|
**Outcome:** ❌ No true SSRF sinks identified - All outbound HTTP requests use hardcoded or configuration-based destinations
|
|
|
|
---
|
|
|
|
**SSRF vs Open Redirect - Technical Distinction:**
|
|
|
|
| Characteristic | SSRF | Open Redirect (This Vulnerability) |
|
|
|---|---|---|
|
|
| **Server Behavior** | Server makes HTTP request to attacker-controlled URL | Server sends HTTP 3xx redirect to client |
|
|
| **Request Origin** | Server's network context | Client's network context |
|
|
| **Access to Internal Services** | Yes - server can reach internal networks | No - client cannot reach internal networks from external position |
|
|
| **Data Exfiltration** | Yes - server returns internal service responses | No - server never sees internal service data |
|
|
| **Network Boundary Bypass** | Yes - server is inside the network | No - redirect fails from external client |
|
|
| **HTTP Status Codes** | 200 OK (or error from internal service) | 303 See Other (redirect to client) |
|
|
|
|
**Why This Matters for Classification:**
|
|
|
|
The analysis phase correctly identified that the application allows arbitrary redirect URIs to be registered without validation. However, the **exploitation mechanism** does not meet the SSRF threat model:
|
|
|
|
- **SSRF Definition:** Server-Side Request Forgery occurs when an attacker can cause the server to make HTTP requests to arbitrary destinations, leveraging the server's network position and credentials.
|
|
|
|
- **This Vulnerability:** The server generates a redirect response (HTTP 303) that instructs the client's browser to navigate to an arbitrary URL. The server itself never makes the request.
|
|
|
|
**Attempted Bypass Techniques:**
|
|
|
|
To ensure thorough testing, the following bypass attempts were made to see if the redirect could be leveraged into true SSRF:
|
|
|
|
1. ❌ **Multiple Protocol Tests:** Tried `file://`, `gopher://`, `ftp://` - All accepted in registration but still result in client-side redirects
|
|
2. ❌ **Redirect Chaining:** Attempted to chain redirects to see if server would follow - No server-side request initiated
|
|
3. ❌ **DNS Rebinding Simulation:** Cannot be tested externally, but would not matter since redirect is client-side
|
|
4. ❌ **SSRF via Request Smuggling:** OAuth flow doesn't involve request parsing that could be smuggled
|
|
|
|
**Actual Security Impact:**
|
|
|
|
While not SSRF, this vulnerability still has security implications:
|
|
|
|
1. **Open Redirect Risk:** Attackers can redirect users to phishing sites via trusted inou.com domain
|
|
2. **OAuth Code Leakage:** If an attacker can register a client with their own domain, they receive the authorization code when users authorize
|
|
3. **Network Topology Disclosure:** Error messages and timing differences may reveal which internal IPs/ports exist
|
|
4. **Authorization Code in URL:** Codes appear in URL parameters of the redirect, violating OAuth security best practices (should use POST-based flows for sensitive redirects)
|
|
|
|
**Recommended Fix:**
|
|
|
|
While this is not SSRF, the underlying vulnerability (unrestricted redirect URIs) should still be fixed:
|
|
|
|
```go
|
|
// In /repos/inou-portal/portal/mcp_http.go, before line 131:
|
|
func validateRedirectURI(uri string) error {
|
|
parsed, err := url.ParseRequestURI(uri)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid URI format: %w", err)
|
|
}
|
|
|
|
// Require HTTPS for all redirect URIs
|
|
if parsed.Scheme != "https" {
|
|
return fmt.Errorf("only HTTPS redirect URIs allowed")
|
|
}
|
|
|
|
// Block private IP ranges
|
|
if ip := net.ParseIP(parsed.Hostname()); ip != nil {
|
|
if ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
|
return fmt.Errorf("private/internal IP addresses not allowed")
|
|
}
|
|
}
|
|
|
|
// Domain allowlist for production
|
|
allowedDomains := []string{"claude.ai", "anthropic.com"}
|
|
hostname := strings.ToLower(parsed.Hostname())
|
|
allowed := false
|
|
for _, domain := range allowedDomains {
|
|
if hostname == domain || strings.HasSuffix(hostname, "."+domain) {
|
|
allowed = true
|
|
break
|
|
}
|
|
}
|
|
if !allowed {
|
|
return fmt.Errorf("redirect domain not in allowlist")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
**Conclusion:**
|
|
|
|
After exhaustive exploitation attempts across multiple attack vectors and internal targets, I have determined with high confidence that **SSRF-VULN-01 is a FALSE POSITIVE for SSRF classification**. The vulnerability is correctly identified as a lack of redirect URI validation, but the exploitation mechanism (HTTP 303 client-side redirect) does not allow server-side network boundary bypass or internal service access.
|
|
|
|
The vulnerability should be reclassified as:
|
|
- **Type:** Open Redirect + OAuth Security Misconfiguration
|
|
- **Severity:** Medium (was incorrectly rated High for SSRF impact)
|
|
- **Exploitability:** High (unauthenticated registration, no validation)
|
|
- **Impact:** Phishing, OAuth code theft, but NOT internal network access
|
|
|
|
**Exploitation Classification Decision Framework Applied:**
|
|
|
|
> "Is this preventing factor a security implementation designed to stop this attack, or an external operational constraint?"
|
|
|
|
**Answer:** Neither. The "prevention" is the fundamental design of HTTP redirects - they are client-side by definition in the HTTP specification (RFC 7231). This is not a security control that could be bypassed; it's the architectural reality of how `http.Redirect()` functions.
|
|
|
|
The correct classification is: **FALSE POSITIVE** - The vulnerability does not enable Server-Side Request Forgery.
|
|
|