Web › Module 1 › Lesson 3
SSRF as an Access Control Failure
A01:2025 SSRF — allowlist on YOUR lab only.
Visual · ssrf_server_fetch
SSRF: 0.0.1:8765. Allowlist literacy — never unauthorized cloud metadata fetches.
Opening
SSRF is not “open a port.” It is your server fetching a URL the caller chose — into networks the caller should not reach.
Under OWASP Top 10:2025, Server-Side Request Forgery is called out inside Broken Access Control (A01): the application’s network position becomes unauthorized reach. Webhook preview, PDF renderer, image importer, “fetch this link” — if the server performs a request to a client-influenced URL, attackers aim that fetch at loopback admin panels, internal HTTP APIs, or link-local metadata endpoints on workloads that can reach them. This is ORIGINAL Cyberlium teaching — attack literacy first. Practical commands start by identifying
1. The mechanism: untrusted URL → server-side fetch → trusted network view
Browsers are sandboxed; servers often sit on private networks with access to admin ports and sibling services. When the server fetches attacker-controlled URLs, the response (or timing/errors) returns through the app. Blind SSRF: side effects only. Non-blind: body echoed. Common sinks: url=, link=, webhook=, avatar fetchers. The vulnerability is trusting client input as a destination. Attacker goal: reach what their laptop cannot — internal status pages, cloud metadata on the instance (named as risk for YOUR workloads), or file-like schemes if the library allows them.
Command guide
A01 BAC — The mechanism
═══ INSTALL ═══
Linux (Debian/Ubuntu):
Command — copy this
sudo apt install curl
macOS: Built-in
Windows: Built-in (PowerShell: Invoke-WebRequest)
═══ COMMANDS ═══
Command — copy this
SAFE="http://127.0.0.1:8765"
Command — copy this
curl -sS -m 3 -D - "$SAFE/health" | head -n 16 curl -sS -m 3 "$SAFE/status" | head -n 12
2. Why metadata and localhost matter — named, not a cloud exploit kit
Cloud instance metadata endpoints are high-value IF an SSRF exists on a workload that can reach them. That sentence is literacy for reading reports and hardening YOUR workloads (IMDSv2 hop limits, eliminate SSRF sinks). It is NOT permission to fetch metadata URLs from a random lab laptop against accounts you do not own. Loopback and private ranges matter because the server can often reach them while the attacker cannot — demonstrate only on servers YOU run under cyberlium-lab. DNS rebinding and URL parser tricks defeat naive blocklists. Allowlisting schemes + hosts you intend is the durable fix direction.
Command guide
A01 BAC — Why metadata and localhost matter - named, not a cloud exploit kit
═══ INSTALL ═══
Linux (Debian/Ubuntu):
Command — copy this
sudo apt install curl
macOS: Built-in
Windows: Built-in (PowerShell: Invoke-WebRequest)
═══ COMMANDS ═══
Command — copy this
SAFE="http://127.0.0.1:8765"
Command — copy this
curl -sS -m 3 -I "$SAFE/" | head -n 12
3. Shipping list: allowlist, no raw URL fetch, egress control
Prefer: map client choice to server-side IDs (“fetch template 7”) not free-form URLs. If URLs are required: allowlist https + exact hosts; block private/link-local ranges in YOUR policy; disable redirects or re-validate after redirect; deny file:// and exotic schemes; use dedicated egress with deny-by-default. For cloud YOU administer: require IMDSv2, restrict roles, eliminate SSRF sinks. Write findings as “server fetches client URL without allowlist.”
Command guide
A01 BAC — Shipping list
═══ INSTALL ═══
Linux (Debian/Ubuntu):
Command — copy this
sudo apt install curl
macOS: Built-in
Windows: Built-in (PowerShell: Invoke-WebRequest)
═══ COMMANDS ═══
Command — copy this
SAFE="http://127.0.0.1:8765"
Command — copy this
curl -sS -m 3 "$SAFE/health" | head -n 10 curl -sS -m 3 "$SAFE/status" | head -n 10
4. Local allowlist demo shape (identify DEMO, then SAFE)
168.0.1/ — A tiny Python allowlist that only accepts http://127.0.0.1:8765/health and /status is enough literacy. Hardcode HOST="127.0.0.1". Refuse argv that rewrites HOST. Do not fetch link-local metadata. Empty notes fail. Notes that list unauthorized cloud targets fail ethics.
5. What you record: mechanism, allowlist vs blocklist, ethics
Date (UTC). SSRF = server fetches attacker-influenced URL (A01:2025). Blind vs non-blind. Identify banner of DEMO or SAFE. Fix: allowlist / no free URL. Ethics: NEVER real cloud metadata fetches against unauthorized accounts; NEVER hydra/nmap the LAN; NEVER scan stranger internal nets. Path: $HOME/cyberlium-lab/ssrf-a01-notes.txt, chmod 600. Legal: original Cyberlium — not official OWASP certification.
6. Wrong vs right: cloud-metadata PoC vs allowlist literacy on YOUR lab
Worked failure — same word “SSRF,” opposite blast radius. Right never needs a stranger’s cloud.
Wrong
Fetch cloud metadata from unauthorized accounts. SSRF-scan corporate ranges without RoE. Hydra 192.168.0.1 because it is a router. Abuse a classmate webhook to pivot.
Right
Identify DEMO; if router, use 127.0.0.1:8765. Name the fetch mechanism and allowlist shipping list. Lock ssrf-a01-notes.txt under $HOME/cyberlium-lab, chmod 600. Never unauthorized cloud metadata recipes.
Run identify, start the loopback lab, curl allowlisted paths. The helper does not fetch cloud metadata.
Command guide
ssrf_a01_lab.sh — DEMO identify + allowlist on 127.0.0.1:8765
═══ INSTALL ═══
Linux (Debian/Ubuntu):
Command — copy this
sudo apt install curl sudo apt install nmap sudo apt install python3
macOS:
Command — copy this
brew install nmap brew install python3
Windows: Built-in (PowerShell: Invoke-WebRequest)
Command — copy this
choco install nmap # or download https://nmap.org/download.html
Download https://python.org/downloads/
═══ COMMANDS ═══
Command — copy this
cd "$HOME/cyberlium-lab"
Command — copy this
SAFE="http://127.0.0.1:8765"
Command — copy this
cat > ssrf_allowlist_demo.py << 'PY'
"""Allowlist literacy on loopback only. Never fetch cloud metadata."""
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs
HOST = "127.0.0.1" # hardcoded — do not take argv for HOST
PORT = 8765
if HOST != "127.0.0.1":
raise SystemExit("refusing non-loopback bind")
ALLOWED = {f"http://{HOST}:{PORT}/health", f"http://{HOST}:{PORT}/status"}
def may_fetch(url: str) -> bool:
return url in ALLOWED
class Handler(BaseHTTPRequestHandler):
def log_message(self, fmt, *args):
print("[demo]", fmt % args)
def _send(self, code: int, body: str):
data = body.encode("utf-8")
self.send_response(code)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def do_GET(self):
u = urlparse(self.path)
qs = parse_qs(u.query)
if u.path == "/health":
return self._send(200, "ok health")
if u.path == "/status":
return self._send(200, "ok status")
if u.path == "/preview":
target = (qs.get("url") or [""])[0]
if not may_fetch(target):
return self._send(403, "DENY not on allowlist")
return self._send(200, "ALLOW would fetch (lab does not proxy): " + target)
return self._send(
200,
"Cyberlium A01 SSRF lab. DEMO writeup: http://192.168.0.1/
"
"GET /health /status /preview?url=http://127.0.0.1:8765/health
",
)
print("bind", HOST, PORT)
print("allowlist", ALLOWED)
print("demo_writeup_url http://192.168.0.1/")
print("ethics: NEVER fetch cloud metadata; NEVER hydra/nmap the LAN")
print("legal: original Cyberlium — not official OWASP certification")
HTTPServer((HOST, PORT), Handler).serve_forever()
PYCommand — copy this
cat > a01_ssrf_practical.sh << 'SH' SAFE="http://127.0.0.1:8765" curl -sS -D - "$SAFE/preview?url=http://127.0.0.1:8765/health" echo curl -sS -D - "$SAFE/preview?url=http://127.0.0.1:8765/admin" echo SH
Command — copy this
{Mission: ssrf-a01-notes.txt in cyberlium-lab (mode 600)
1) 0.0.1:8765.2) Run the allowlist demo; record ALLOW/DENY curls. 3) Fill $HOME/cyberlium-lab/ssrf-a01-notes.txt, chmod 600. No cloud metadata fetches, no LAN hydra/nmap.
Stuck? Ask Cyberlium AI Mentor
If “I cannot learn SSRF without hitting AWS metadata” still feels true, ask for a hint — not a metadata recipe. Try: "Hint only: why SSRF is A01, why allowlists beat blocklists, which curls hit /preview on 127.0.0.1:8765, and where locked ssrf-a01-notes.txt lives?"
You now treat SSRF as an access-control failure under OWASP Top 10:2025 A01 — server fetch beyond intended destinations — with allowlist literacy, identified demo asset, and locked notes. Original Cyberlium — not official OWASP certification. Next — Lab — Bug Bounty Finding Demo (A01) — scope, loopback IDOR, report draft.
Knowledge Check
APPLY: An app fetches a user-supplied preview URL and returns the body. What is the A01 mechanism, and what is the fix direction?
Multiple choice
Knowledge Check
APPLY: True or False: Because A01:2025 names SSRF, you may fetch real AWS instance metadata from any account “for homework.”
True or False
Knowledge Check
APPLY: curl http://192.168.0.1/ shows Huawei Router Admin. What do you do for the SSRF lab?
Multiple choice