← Return to Ledger
MODULE_11 // SERVER PIVOT & LOGIC DECONSTRUCTION

SSRF & Business Logic

OPERATIONAL OBJECTIVE

Two attack classes with one shared trait: the application does exactly what you tell it to, just not what the developer intended. SSRF makes the server fetch URLs on your behalf — including internal services it was never meant to reach. Business logic bugs exploit gaps in the application's own rules — price checks, quantity limits, workflow steps the developer forgot to enforce. Neither class is detectable by scanners. Both require human understanding of how the system is supposed to work.

Part 1 — Server-Side Request Forgery (SSRF)

SSRF occurs when a web application fetches a remote resource based on a URL supplied by the user — and doesn't restrict which URLs are permitted. The server makes the request from its own network position, which means it can reach internal services, cloud metadata endpoints, and backend systems that are completely inaccessible from the internet.

The attacker never talks directly to the internal network. Instead they weaponize the application's own HTTP client — making it act as a proxy into infrastructure it was never meant to expose.

Where SSRF Hides — Common Injection Points

Any feature that fetches a URL on the server side is a potential SSRF vector. Look for:

🔍 How to spot it in requests Look for parameters named: url, uri, link, src, dest, redirect, path, next, target, callback, fetch, load, host, endpoint. Any parameter that looks like it points somewhere is worth testing.

SSRF — How the Attack Works

Actor
Step
Attacker
POST /fetch-preview {"url":"http://169.254.169.254/latest/meta-data/"} User-supplied URL
App Server
Server's HTTP client fetches the URL from its own network position Bypasses firewall
Cloud Metadata
Returns IAM credentials, instance role, token 169.254.169.254 only reachable internally
App Server
Embeds response in HTTP reply to attacker Full response content returned
Attacker
Receives cloud credentials, internal service data Attack complete

High-Value SSRF Targets

Target URLWhat It ExposesSeverityWorks On
http://169.254.169.254/latest/meta-data/ AWS EC2 instance metadata: IAM role names, temporary credentials, instance ID, AMI info Critical AWS EC2 instances
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE Actual AWS access key, secret key, session token — usable immediately to call AWS APIs Critical AWS EC2 with IAM role
http://metadata.google.internal/computeMetadata/v1/ GCP service account tokens, project info, SSH keys Critical Google Cloud instances
http://169.254.169.254/metadata/instance?api-version=2021-02-01 Azure VM metadata, managed identity tokens Critical Azure VMs
http://localhost/ http://127.0.0.1/ Admin panels, internal APIs, services bound to loopback that aren't exposed externally Critical Any server
http://192.168.x.x/ http://10.x.x.x/ Internal network services: databases, admin dashboards, internal APIs, other app servers High Any server with internal network
file:///etc/passwd Local file read if the HTTP client allows file:// scheme High Servers with loose URL scheme allowlist

Blind SSRF

In many cases the server fetches the URL but doesn't return the response body to you — only a success/fail status. This is blind SSRF. You can't read the internal service response directly, but you can still prove it by using an out-of-band detection technique.

Detection method: Use a unique URL that will generate a DNS lookup or HTTP request to a server you control. Burp Collaborator (built into Burp Suite Pro) generates a unique subdomain — any DNS resolution or HTTP request to it proves the server made an outbound connection.

Blind SSRF detection using Burp Collaborator# 1. In Burp Suite → Collaborator → Copy unique URL:
#    https://abc123xyz.oastify.com

# 2. Inject it into the SSRF injection point:
POST /import-feed
{"url": "http://abc123xyz.oastify.com/ssrf-test"}

# 3. Check Collaborator tab — if you see a DNS lookup
#    or HTTP request arrive, blind SSRF is confirmed.

# Alternative: webhook.site (free, no Burp Pro needed)
{"url": "https://webhook.site/your-unique-id"}
🏆 Why blind SSRF still pays Even without reading internal responses, blind SSRF confirms the server makes outbound requests to attacker-controlled destinations. This enables: port scanning of the internal network (by timing differences between open/closed ports), confirming cloud metadata reachability (different response times), and chaining with other vulnerabilities. Many programs pay $500–$3,000 for confirmed blind SSRF with a solid out-of-band PoC.

SSRF Filter Bypass Techniques

Applications often implement blocklists to prevent SSRF — blocking 127.0.0.1, localhost, and 169.254.169.254. These filters are consistently bypassable:

Alternative IP Representations
127.0.0.1 can be written as:
127.1 — short form
2130706433 — decimal
0x7f000001 — hex
0177.0.0.1 — octal
::1 — IPv6 loopback
All resolve to the same loopback address.
DNS Rebinding
Register a domain that initially resolves to a public IP (passes the allowlist check), then switches to an internal IP (127.0.0.1) on the actual fetch. The server's DNS client resolves the address twice — the second resolution returns the internal target.

Tools: singularity DNS rebinding server.
URL Redirects
Host a redirect on a server you control:
https://yourserver.com/r → 301 → http://127.0.0.1/admin

If the validator checks the initial URL but the HTTP client follows redirects automatically, the final destination is internal. Many HTTP libraries follow 3xx redirects by default.
URL Parser Confusion
Different parsers read the same URL differently:
http://evil.com@127.0.0.1/
http://127.0.0.1#evil.com
http://[::ffff:127.0.0.1]/

The validator may parse the "host" as evil.com while the HTTP client resolves to 127.0.0.1.
Scheme Variations
If the application blocks http:// but accepts other schemes:
https://127.0.0.1/
file:///etc/passwd
gopher://127.0.0.1:25/ (SMTP injection)
dict://127.0.0.1:11211/ (memcached)

Gopher can send arbitrary TCP payloads — usable to interact with Redis, Memcached, or internal APIs.
Allowlisted Domain Bypass
App only allows URLs containing a specific domain. Bypass via open redirects on that domain:
https://trusted.com/redirect?to=http://127.0.0.1

Or: register a subdomain of a trusted domain if you can find an open redirect or subdomain takeover on their infrastructure.
⚡ Lab 1 — SSRF Simulation Engine

Simulate server-side URL fetching. Toggle the SSRF filter and test different URL types — including bypass vectors that circumvent naive blocklists.

Target URL (injected into server-side fetch)
Attack payloads
Filter bypass vectors (test when filter is ON)
Server Response Log
[idle] Enter a URL and click Fetch to simulate a server-side request.
⚡ Lab 2 — Blind SSRF Out-of-Band Detector

Simulate submitting a Collaborator URL and watching for the server's callback. This is how you prove blind SSRF when no response is returned to you directly.

Your Collaborator / Webhook URL
Out-of-Band Callback Listener
Waiting for server callbacks...
// DNS lookups and HTTP requests will appear here

Part 2 — Business Logic Vulnerabilities

Business logic flaws aren't bugs in the code — the code works exactly as written. The flaw is in the design: a workflow step the developer assumed would always happen, a constraint they forgot to enforce, or an edge case they never considered. Scanners can't find them because the requests look completely legitimate. Only a human who understands how the feature is supposed to work can spot them.

🔍 The core question for every feature Ask: "What is this feature supposed to prevent, and is that prevention actually enforced?" A discount code that can only be used once — is that enforced server-side, or just client-side? A price displayed in the cart — does the server recalculate it, or trust the client? A workflow step (verify email before transfer) — can it be skipped?

Category 1: Price & Value Manipulation

Applications that trust client-supplied prices, discount amounts, or transaction values are directly exploitable. The fix is simple (never trust client-side prices — always recalculate server-side), but the mistake is common.

Intercept checkout request in Burp — modify the pricePOST /api/checkout HTTP/1.1
Content-Type: application/json

{
  "items": [{"id": "prod_9x2", "quantity": 1, "price": 999.00}],
  "total": 999.00
}

# Modify in Burp Repeater:
{
  "items": [{"id": "prod_9x2", "quantity": 1, "price": 0.01}],
  "total": 0.01
}

# If server trusts client price → item purchased for $0.01

Category 2: Negative Value & Integer Boundary Abuse

Input validation often checks for "too high" but forgets to check for negative values. This can reverse expected transaction flows.

Negative quantity → account credit instead of debitPOST /api/refund
{"order_id": "ORD-1234", "quantity": -5}

# Expected: server refuses negative quantity
# Vulnerable: server calculates refund * -5 = credits account

# Negative price on a coupon:
POST /api/apply-coupon
{"code": "SAVE10", "amount": -100}
# If amount is trusted → $100 added to cart instead of deducted

Category 3: Race Conditions

When two requests hit the server simultaneously, both can pass a check before either one has written its result. This is how single-use coupons get used multiple times, how gift card balances get over-spent, and how referral bonuses get claimed repeatedly.

Race condition on a single-use coupon — Burp Turbo Intruder# Normal flow:
# 1. Check coupon is unused → 2. Apply coupon → 3. Mark as used

# Race condition:
# Thread A: Check coupon (unused) ✓
# Thread B: Check coupon (unused) ✓  ← both pass before either writes
# Thread A: Apply coupon → mark used
# Thread B: Apply coupon → mark used   ← coupon applied twice!

# In Burp Turbo Intruder — send the same request 20 times in parallel:
# engine=Engine.THREADED → all fire simultaneously
# Look for 2+ success responses to the same coupon code

Category 4: Workflow Step Skipping

Multi-step processes often have security checks at one step but not at the step that actually performs the action. If you can jump directly to the final step, the check never runs.

Skipping an email verification step# Intended flow:
# Step 1: Submit email change request
# Step 2: Click verification link sent to OLD email
# Step 3: Change is confirmed

# Attack: Submit Step 1, then jump directly to the endpoint
# that handles "change confirmed" (Step 3) without Step 2.
# Some apps check for the verification only at Step 2 —
# if Step 3 doesn't re-verify, the email is changed without proof of ownership.

# Same pattern: order workflows, payment confirmation, 2FA setup,
# KYC verification before high-value actions.

Category 5: Discount & Coupon Logic

Category 6: Trust Boundary Violations

Applications often have implicit trust assumptions that aren't enforced. A user-tier action endpoint that checks role on page load but not in the API. An admin function that's hidden in the UI but fully accessible via direct API call. A "read-only" API key that accepts write operations.

Hidden admin endpoint accessible by regular users# Frontend: admin panel hidden, links not rendered for non-admins
# Backend: no authorization check on the actual endpoint

GET /api/admin/users      → 403 (correctly checked)
GET /admin/export-users   → 200 (HTML route — no auth check)
POST /api/admin/set-role  → 200 (forgot the auth middleware)
⚡ Lab 3 — Business Logic Transaction Engine

Interact with a simulated e-commerce checkout. The server-side validation switch controls whether the backend re-validates pricing. Test every attack category.

Cart State (editable — like Burp Repeater)
Product: Crypto Ledger Pro
Base price: $299.00
quantity
unit_price (USD)
coupon_code
Quick attack presets
Server Response
Waiting for checkout submission...

Real Bug Bounty Findings

Critical — Cloud Credential Theft
SSRF → AWS Metadata → IAM Credentials
PDF generation feature accepted arbitrary URLs. Attacker submitted http://169.254.169.254/latest/meta-data/iam/security-credentials/app-role. Full AWS access key, secret, and session token returned in the generated PDF. Attacker had full read access to S3 buckets containing PII of millions of users.
$25,000+
Critical — Internal Admin Access
SSRF → localhost:8080/admin → RCE
Image import via URL. Server ran an internal management service on port 8080 with no auth (assumed unreachable externally). SSRF reached it. Admin interface had a file upload feature. Uploaded a web shell. Remote code execution on the application server.
$15,000
High — Financial Loss
Negative Quantity → Account Credit
E-commerce platform's refund endpoint accepted negative quantities. POST {"quantity": -10} on a $50 item credited $500 to the account. No maximum refund check. Attacker purchased $0.01 items, refunded with quantity -1000, accumulated significant balance.
$6,500
High — Coupon Abuse
Race Condition on Single-Use Coupon
50%-off coupon limited to one use per account. Burp Turbo Intruder sent 25 parallel requests using the same coupon code. 8 requests succeeded before the "used" flag was written. $4,000 item purchased for $0.50 total across stacked successful redemptions.
$4,000
High — Blind SSRF
Webhook URL → Internal Network Scanning
Webhook notification URL wasn't validated. Burp Collaborator confirmed the server made outbound HTTP requests. By systematically targeting internal RFC-1918 ranges and measuring response time differences, attacker mapped 14 internal services including a Kubernetes API server.
$3,200
Medium — Price Manipulation
Client-Supplied Price Trusted at Checkout
Cart total in the POST body was never server-side recalculated. Changing "total": 299.00 to "total": 0.01 in Burp — order fulfilled at $0.01. Affected all digital product purchases. Physical goods had a separate validation that caught it.
$1,800

Testing Methodology

SSRF Testing Checklist

1
Map all URL-consuming features

Search for parameters named url, link, src, fetch, callback, webhook, endpoint, redirect. Also check file import, PDF generation, and link preview features even when no obvious URL parameter exists.

2
Test for basic SSRF

Submit your Burp Collaborator URL. Check for DNS callbacks — this confirms outbound connections before any internal targeting. If you get a ping, SSRF is present.

3
Target cloud metadata if applicable

If the app is hosted on AWS/GCP/Azure, try http://169.254.169.254/. Try bypass representations if blocked. This is the highest-impact SSRF target.

4
Test loopback and internal ranges

Try http://localhost/, http://127.0.0.1/, and common internal ports: 8080, 8443, 9200 (Elasticsearch), 6379 (Redis), 11211 (Memcached), 2375 (Docker). Note response differences — timing or content changes indicate port is open.

5
Test bypass vectors if filtered

If 127.0.0.1 is blocked, try 127.1, 0x7f000001, 2130706433, [::1]. Try open redirect on an allowlisted domain. Use DNS rebinding for complex filter bypass.

Business Logic Testing Checklist

1
Intercept every transaction in Burp

Capture checkout, refund, coupon application, subscription change requests. Look for any numeric value (price, quantity, discount, amount) that originates from the client side.

2
Tamper with every numeric parameter

Try: set price to 0.01, set quantity to -1, set discount to 101%, set total to 0. Send in Burp Repeater. Does the server recalculate, or trust your value?

3
Test coupon and discount limits

Apply the same coupon twice. Apply multiple different coupons. Try a coupon from another user's account. Try a coupon after its expiry date. Try applying coupons in different orders.

4
Look for skippable workflow steps

Identify multi-step processes: checkout, registration, verification flows. Try accessing later steps directly without completing earlier ones. Does the final action endpoint verify all prerequisites?

5
Test race conditions on limited actions

Single-use coupons, limited-stock items, referral bonuses, one-click purchases. Use Burp Turbo Intruder to send 20–50 parallel requests. Look for multiple success responses to the same idempotent-expected action.

Essential Tools for This Chapter

ToolPurposeKey Usage
Burp Collaborator Out-of-band detection for blind SSRF Burp → Collaborator → Copy to clipboard. Inject URL. Check for DNS/HTTP callbacks. Pro feature — use webhook.site as a free alternative.
Burp Repeater Manual parameter tampering for logic bugs Intercept any transaction → Send to Repeater → Modify price/quantity/coupon fields → Resend → Compare responses.
Burp Turbo Intruder Parallel request sending for race conditions Right-click → Extensions → Turbo Intruder. Use the race condition template. Sends 20+ requests simultaneously to exploit timing windows.
webhook.site Free out-of-band callback listener Visit webhook.site, get a unique URL. Inject it as the SSRF/blind SSRF payload. Callbacks appear in real-time on the dashboard.
PortSwigger Labs Guided hands-on SSRF and logic labs SSRF: basic, blind, against another backend. Business logic: excessive discount, inconsistent handling, authentication bypass via flawed state machine.

Chapter 11 Operational Checklist

0 / 14
COMPLETE
PortSwigger Labs
Hands-On Drills
Knowledge Checks
Q1 — SSRF Impact

Why is SSRF against a cloud metadata endpoint rated Critical while SSRF against an external URL is typically only Medium? What's the difference in impact and what makes 169.254.169.254 specifically dangerous?

Q2 — Proving Blind SSRF

You inject a URL into a webhook field. The server returns {"status": "saved"} but no response content. How do you prove SSRF is present? Walk through the exact steps using Burp Collaborator or webhook.site.

Q3 — Filter Bypass

The application blocks requests containing "127.0.0.1" and "localhost". Name three alternative representations you would try to reach the loopback address, and explain why each one works.

Q4 — Business Logic vs Technical Bug

Explain why business logic vulnerabilities can't be detected by automated scanners. What does a scanner look for, and why is that approach blind to logic flaws? Give a concrete example.

Q5 — Race Condition Mechanics

Describe the exact timing window that a race condition exploits. Why does sending 20 requests in parallel sometimes result in multiple successes on an action designed to succeed only once?