Cyberlium

Web › Module 1 › Lesson 3

BeginnerModule 1Lesson 3/5

SSRF as an Access Control Failure

A01:2025 SSRF — allowlist on YOUR lab only.

15 min+40 XP3 quiz
Module progress3 of 5

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()
PY

Command — 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

1

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

2

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

3

APPLY: curl http://192.168.0.1/ shows Huawei Router Admin. What do you do for the SSRF lab?

Multiple choice

← Previous

Answer all 3 knowledge checks to continue. (0/3 answered)