June 11, 2026
Blind SSRF: You Can’t See the Response. You Don’t Need To.
The server is still making requests. You just have to find a different way to know that. Part 3 of the SSRF series.
0x4rt1st
3 min read
Part 3 of the SSRF series. Parts 1 and 2 were about reflected SSRF — we found the
dateserverparameter, confirmed the vulnerability, brute-forced hidden endpoints, and read/etc/passwdstraight from the server's filesystem. If you skipped those, go back. This part won't make much sense without them.
Now. In part 1, I mentioned there are two types of SSRF and we'd get to the second one later. This is later.
What Changes
With reflected SSRF, whatever the server fetches comes back to you in the response. Point it at an internal page — the HTML comes back. Point it at a file — the contents come back. You're seeing everything.
Blind SSRF is the same vulnerability with one thing removed: the output. The server still makes the request. Still reaches out to wherever you point it. But nothing comes back to you. The application just returns its own generic response regardless of what happened internally.
That one missing piece changes how you work almost entirely.
Same Application, No Output
Same DefendTech lab from the previous parts. Same dateserver parameter. But this time, point it at the application itself and see what comes back:
Nothing. Just that generic message. In part 1 and 2, we'd get the full HTML of whatever we requested. Here the application swallows it and returns the same thing it would return for literally any failed request.
No way to read through it. So how do you even know the vulnerability is there?
Confirming It the Same Way We Started
Remember part 1 — the very first thing we did to confirm the SSRF was set up a netcat listener and point the parameter at our own machine. The application response didn't tell us anything. The listener did.
Same move here.
nc -nlvp 4444
dateserver=http://10.10.14.138:4444&date=2024-01-01nc -nlvp 4444
dateserver=http://10.10.14.138:4444&date=2024-01-01
The application returned its usual nothing. But the listener caught the connection — coming from 10.129.40.161, which is the server. It made the request. The vulnerability is there.
That's the first lesson with blind SSRF: when the application won't tell you anything, you make the server tell you directly.
Finding the Gap
Confirming it is one thing. Actually doing something useful with it is harder. With reflected SSRF we could read responses — that's gone now. But before giving up on enumeration entirely, let's look more carefully at what the application actually does.
Point it at port 80 — open, web server running there:
"Date is unavailable. Please choose a different date!"
Now point it at port 81 — nothing running there:
"Something went wrong!"
Two different ports. Two different messages. The application can't show us what the server fetched — but it can't hide the fact that it behaved differently when the connection succeeded versus when it got refused. Open port, one message. Closed port, another.
That's the gap. Small, but it's enough.
Port Scanning Through It
In part 1, we port scanned using the difference in response sizes from reflected output. Here we do the same thing, just using the difference between those two error messages instead.
Filter out the closed-port message, and anything that survives is an open port:
bash
ffuf -w ports.txt \
-u http://10.129.40.161/ \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "dateserver=http://127.0.0.1:FUZZ/index.php&date=2024-01-01" \
-fr "Something went wrong!"ffuf -w ports.txt \
-u http://10.129.40.161/ \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "dateserver=http://127.0.0.1:FUZZ/index.php&date=2024-01-01" \
-fr "Something went wrong!"
Port 5000. Everything else got filtered. Something is running there and responding — we just can't read what it is.
What You Actually Get
Blind SSRF is not reflected SSRF with a blindfold on. The gap in capability is real. No reading files. No dumping admin pages. The file:// trick from part 2 won't help — the file gets read but you never see it.
What you're left with is inference. Open ports, like we just found. Whether a file path exists or not — the two-response trick works for filesystem enumeration too, not just ports. Internal hostnames. Service fingerprinting by port number alone.
It's slower. It gives you less. But finding port 5000 here still tells you something — there's a service running internally that you now know about, that nobody from outside is supposed to know about. That feeds whatever comes next.
The server is still making requests on your behalf. You're just reading the side effects now instead of the output.
Next part — prevention. What it actually takes to stop all of this.