SSRF: The Complete Practical Guide to Server-Side Request Forgery
Blind SSRF and Out-of-Band Detection
How to find and exploit blind SSRF: proving the fetch with an out-of-band listener, DNS vs HTTP callbacks, and why blind still reaches metadata.
Published
Blind SSRF is the same bug as the in-band case, minus the payoff of a visible response. The server makes your request, but the app shows you nothing back. That does not make it safe. You confirm it out-of-band, then extract what you need from timing, errors, and side effects. The one change is that execution has to announce itself.
What "blind" means
In a blind SSRF the fetch happens but the response never reaches you. The feature returns a generic success, or nothing, or an error that does not include the fetched body. A webhook sender, a background importer, or an analytics ping are classic blind sinks: they fire the request as a side task and never surface the result.
Because there is no response to read, a normal in-band test shows nothing, and the bug looks absent.
Using an out-of-band listener
The fix is to make the request prove itself. Point it at a unique hostname on a server you control that logs inbound DNS and HTTP:
url = http://unique-id.oast.example/When the server fetches that, the request lands in your listener's logs with a timestamp and the source IP. Now you know the SSRF fired, even though the app said nothing. Give each injection point a different subdomain so the callback tells you exactly which input is vulnerable.
DNS versus HTTP callbacks
Watch which part of the callback actually arrives, because the two tell you different things:
- DNS lookup only, no HTTP connect. The server resolved your hostname but could not or did not complete the HTTP request. Outbound HTTP is likely filtered, but DNS still leaks, which is enough to confirm and even to exfiltrate small data.
- Full HTTP connection. Outbound HTTP works, so you have a stronger primitive and can likely reach internal HTTP services too.
Only DNS hits your listener -> outbound HTTP blocked, DNS open
Full HTTP hits your listener -> outbound HTTP allowedThis distinction shapes everything you try next.
Inferring success from timing and errors
Without a body, differences become your signal. Request internal targets and compare:
- Timing. A fast response suggests the host answered, while a long hang until timeout suggests a filtered port or an unreachable host.
- Error shape. A connection-refused error (fast) versus a timeout (slow) versus a parse error (the service answered with something) each mean different things.
- State changes. If the fetch triggers a side effect you can observe elsewhere, that is confirmation too.
You are reading the shadow the request casts, not the request itself.
Why blind SSRF still reaches metadata
The most important point: blind does not mean low impact. Even with no response body, a blind SSRF that can reach the network can still hit the cloud metadata service and cause the credentials to be requested. The limitation is that you may not see the credentials come back directly, so you lean on out-of-band exfiltration (routing the fetched data back through a hostname you control) or on chaining the request so the side effect is observable. Cloud metadata abuse covers what makes that reachable.
Turning blind into data
Sometimes you can claw a response back out:
- Error-based leakage. If a malformed internal response makes the app throw an error that includes part of the fetched content, the error becomes your read channel.
- DNS exfiltration. Encode small pieces of data into the subdomain of a hostname the server looks up, and read them off your DNS logs.
- Differential responses. Ask yes/no questions where a true condition changes timing or triggers a callback, and binary-search the answer.
Blind SSRF rewards patience and a good listener. Confirm it out-of-band first, then decide whether to escalate toward internal services or the metadata path. Practice it on a free live target.
← Back to SSRF: The Complete Practical Guide to Server-Side Request Forgery