June 10, 2026
SSRF Exploitation: From Reading Internal Pages to Dumping System Files
We already proved the server takes requests from us. Now let’s see how far that actually goes. Part 2 of the SSRF series.
0x4rt1st
4 min read
Part 2 of the SSRF series. If you missed part 1 — we found a
dateserverparameter in a POST request that was passing a full URL to the server, confirmed the SSRF by pointing it at our own machine and catching the incoming connection, then used it to port scan the server and find a service running on port 8000. Go read that first, it sets everything up.
This part is where things get real.
Where We Left Off
At the end of part 1, we had confirmed two things: the SSRF is reflected — meaning the server fetches whatever we point it at and sends the response back to us — and the server is talking to a separate internal host called dateserver.htb that we can't reach directly from the outside.
The natural next question is: what else is running on that host?
Finding What's Hidden
We know dateserver.htb exists. We know it has at least one endpoint — availability.php, the one the application was already calling. But internal servers usually have more than one page. There might be an admin panel, a config file, a debug endpoint — something the developer built assuming nobody from the outside would ever find it.
So let's look. We'll use ffuf to brute-force directories through the SSRF — every request goes to our vulnerable application, which then forwards it to dateserver.htb on our behalf.
ffuf -w /opt/SecLists/Discovery/Web-Content/raft-small-words.txt \
-u http://TARGET/index.php \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "dateserver=http://dateserver.htb/FUZZ.php&date=2024-01-01" \
-fr "Server at dateserver.htb Port 80"ffuf -w /opt/SecLists/Discovery/Web-Content/raft-small-words.txt \
-u http://TARGET/index.php \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "dateserver=http://dateserver.htb/FUZZ.php&date=2024-01-01" \
-fr "Server at dateserver.htb Port 80"One hit that stands out from everything else: admin. Status 200, size 361. Everything else either 404'd or returned the default Apache error page we filtered out. There's an admin.php on dateserver.htb — and it's responding.
Accessing the Admin Panel
Now we point the dateserver parameter directly at it:
dateserver=http://dateserver.htb/admin.php&date=2024-01-01dateserver=http://dateserver.htb/admin.php&date=2024-01-01
The full admin dashboard came back. because from the server's perspective, this request is coming from inside the network. dateserver.htb trusts requests from the web server. And since we control what the web server requests, we inherit that trust completely.
That's the core idea behind SSRF. You're not breaking in — you're borrowing the server's identity.
Going Beyond HTTP — Reading Local Files
Here's where it gets even more interesting. The dateserver parameter accepts a URL, and a URL isn't limited to http://. Different URL schemes do different things. And one of them — file:// — tells the server to open a file from its own filesystem instead of making a network request.
So instead of pointing it at a web server, let's point it at a local file:
dateserver=file:///etc/passwd&date=2024-01-01dateserver=file:///etc/passwd&date=2024-01-01
/etc/passwd is just the start — it's the obvious target because it's always readable. But the same technique works on anything the web server process has permission to read. The application's own source code. Configuration files with database credentials. Environment files with API keys. You just need to know — or guess — the path.
This is why the file:// scheme is one of the first things you test when you find an SSRF. The jump from "server makes HTTP requests" to "server reads its own files" is just one URL scheme change.
i recommend u to take a look at my list covering file inclusion vulnerabilities , it's so much interessting and i hope that u can find value in it .
https://medium.com/@monceffennan1240/list/file-inclusion-attacks-bfcc789d7dfa
The Gopher Protocol — Sending Arbitrary Data
There's one more URL scheme worth knowing about: gopher://.
With http://, if the server is using a function like file_get_contents() , you're limited to GET requests. You can fetch pages, read responses — but you can't send a POST request with a body. That's a real limitation. What if the internal endpoint you found requires a login? What if there's a form you need to submit?
Gopher is an old protocol — predates HTTP — but it has a property that makes it extremely useful for SSRF exploitation: it lets you send arbitrary bytes to any TCP socket. Which means you can craft a raw HTTP POST request yourself and send it through gopher, bypassing the GET-only restriction entirely.
Say we found admin.php requires a password submitted via POST. The raw HTTP request we want to send looks like this:
http
POST /admin.php HTTP/1.1
Host: dateserver.htb
Content-Length: 13
Content-Type: application/x-www-form-urlencoded
adminpw=adminPOST /admin.php HTTP/1.1
Host: dateserver.htb
Content-Length: 13
Content-Type: application/x-www-form-urlencoded
adminpw=adminYou URL-encode the spaces and newlines, prefix it with the gopher scheme and target host, and you get:
gopher://dateserver.htb:80/_POST%20/admin.php%20HTTP%2F1.1%0D%0AHost:%20dateserver.htb%0D%0AContent-Length:%2013%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0A%0D%0Aadminpw%3Dadmingopher://dateserver.htb:80/_POST%20/admin.php%20HTTP%2F1.1%0D%0AHost:%20dateserver.htb%0D%0AContent-Length:%2013%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0A%0D%0Aadminpw%3DadminAnd since this gopher URL is itself being sent inside a POST parameter, you need to URL-encode the whole thing a second time so it survives the transport. Double encoding — it looks ugly, but it's just mechanics.
What makes gopher genuinely dangerous isn't just POST requests. Because it sends raw bytes to any TCP socket, you can use it to talk to internal services that aren't even HTTP — MySQL, Redis, SMTP mail servers, FastCGI. If it listens on a TCP port and you know the protocol, gopher can speak it. There's a tool called Gopherus that generates valid gopher payloads for most of these services automatically, so you don't have to build every byte by hand.
What Just Happened
Let's look at what we pulled off in this part:
We used the SSRF to brute-force hidden endpoints on an internal server we couldn't reach directly. We found an admin panel that has no authentication from the inside. We accessed it and got full admin access without credentials. Then we switched URL schemes and read the server's own /etc/passwd straight from the filesystem. And on top of that, gopher gives us a way to send POST requests and interact with internal non-HTTP services — making SSRF exploitation go well beyond just fetching web pages.
Three URL schemes. Three completely different attack vectors. All through one parameter.
Part 3 — blind ssrf.