July 7, 2026
๐ป When a Proxy Becomes a Spy: Hunting an SSRF That Led Straight Into the Server Room
Hello folks!! ๐
By Yogesh Bhandage
7 min read
Back again with another write-up, and this one's a personal favorite because the bug didn't come from hours of manual clicking โ it came from my own tool quietly waving a little flag going "psstโฆ heyโฆ you might wanna look at this one." ๐ฉ
So grab your chai โ, get comfy, and let me tell you about the day a friendly little proxy endpoint decided it trusted literally everyone on the internet a bit too much.
โ ๏ธ Quick heads-up: The real target is redacted throughout. I'll be using
example.comeverywhere. Please don't go poking at random endpoints without permission โ that's not hacking, that's just volunteering for a very awkward legal email. ๐
So, What Even Is SSRF? ๐ค
SSRF (Server-Side Request Forgery) is a vulnerability where you trick the server into making HTTP requests on your behalf. ๐ญ
Picture it like this: you're standing outside a fancy office building with a strict "employees only" door. You can't get in. But there's a super helpful intern (the server) who is allowed inside, and he'll happily fetch anything you ask for. So instead of breaking in, you just smile and say "hey buddy, could you grab me that file from the back room?" โ and off he goes. ๐โโ๏ธ๐จ
That "back room" is the internal network. Databases, admin panels, cloud metadata endpoints, health-check pages โ all the stuff that's supposed to be firewalled far, far away from the outside world. If the intern never checks where he's being sentโฆ congratulations, you've got yourself an SSRF.
Now, onto the fun part. ๐ฟ
Enter HackLens ๐ฆ
So I've been building my own recon tool called HackLens (github.com/yogeshbhandage/hacklens) โ a bug bounty automation tool that runs straight from your terminal. You point it at a domain, hit enter, and go make a sandwich ๐ฅช while it handles the whole boring-but-crucial part: subdomain enumeration, alive checks, JS & URL collection, secret scanning, and a pile of vuln checks โ then it spits out a clean JSON report and a pretty HTML report you can actually read without crying.
One command. That's the whole vibe:
bash run.sh -d example.com --deep --subsbash run.sh -d example.com --deep --subs
While it was busy enumerating subdomains and hoovering up every URL and endpoint it could find, one particular request in the crawled-endpoints output made me stop mid-sandwich-bite. ๐ฅช๐
It was a WordPress admin-ajax.php call โ and sitting right there in the query string was a parameter named url:
https://example.com/wp-admin/admin-ajax.php?mbuilder_ajax=12&action=proxy&url=http://...https://example.com/wp-admin/admin-ajax.php?mbuilder_ajax=12&action=proxy&url=http://...action=proxyโฆ url=โฆ a server-side proxy handler with a user-controlled destination. ๐จ
Look, if you've done this long enough, a parameter named url sitting in a request is like finding a door labeled "DO NOT OPEN" in a horror movie. You know you're going to open it. It was never a choice. ๐ช๐
The Vibe Check: does it actually fetch what I tell it to? ๐ฏ
First question โ does this thing genuinely go fetch whatever I stuff into the url parameter? Only one way to find out. I pointed it at a domain I control:
...&action=example_proxy&url=http://evil.com...&action=example_proxy&url=http://evil.comAndโฆ it fetched it. ๐ The application reached out to my attacker-controlled domain and cheerfully rendered the content right back to me.
At this point the intern had officially agreed to run errands for a complete stranger off the street. Excellent. But fetching external stuff is only mildly spicy. ๐ถ๏ธ The real question hanging in the air was: would he go inside the building? ๐ข
Turning the Server Against Itself ๐
Time to point the proxy right back at itself. And what better target than the most iconic address in all of hacking โ good ol' localhost:
...&action=example_proxy&url=http://127.0.0.1:80...&action=example_proxy&url=http://127.0.0.1:80And the serverโฆ happily returned content from the service running on 127.0.0.1:80. ๐ฎ
That right there is the "oh no" moment. The moment a mildly-curious bug graduates into a genuine security problem. The server was now reaching into its own internal network โ a place I have absolutely zero business being โ and handing me the results on a silver platter. ๐ฝ๏ธ
Can I Map the Internal Network? (Spoiler: yep) ๐บ๏ธ
Getting a response from port 80 was great, but a single open port is a party of one. ๐ The real prize would be enumerating internal services โ basically using this endpoint as a port scanner that the server runs on my behalf.
So I aimed it at a port I was pretty sure was shut:
...&action=example_proxy&url=http://127.0.0.1:1234...&action=example_proxy&url=http://127.0.0.1:1234And the response came back different from the port 80 one โ not an error I caused, but a genuinely distinct "yeah, nothing's listening there" behavior. ๐
And that's the golden insight right there: open ports and closed ports respond differently.
- Port 80 (open) โ content comes back โ
- Port 1234 (closed) โ different response, connection fails โ
Which means by just cycling the port number, I could sit comfortably on the outside and map out exactly what's listening on the inside. The server had quietly become my personal reconnaissance drone. ๐ธ It wasn't a proxy anymore โ it was an accomplice. ๐ค
The Plot Twist That Bumped It to Critical ๐ฅ
Honestly? I could've stopped here. It was already a solid finding. But then my brain did that thing brains do and whispered "โฆwhat if the internal Apache has its status page exposed?" ๐ โ you know, the mildly cursed intrusive thought every hacker eventually gets.
Here's the context: Apache's /server-status page (from mod_status) is normally locked down to localhost only, because it spills. Like, a lot. Active requests, client IPs, the exact URLs being hit, request methods, internal endpoints โ it's basically the server live-tweeting everything it's doing in real time. ๐ก
And here's the beautiful, terrible part: from the server's own point of view, I am localhost. The proxy was making the request from inside the building. ๐ญ
So instead of guessing internal paths one by one like a caveman ๐ฆด, I let a wordlist do the heavy lifting and fuzzed the path:
...&action=example_proxy&url=http://127.0.0.1/FUZZ...&action=example_proxy&url=http://127.0.0.1/FUZZโฆand one of the hits that came flying back was /server-status. ๐ฏ So naturally, I pointed the proxy straight at it:
...&action=example_proxy&url=http://127.0.0.1/server-status...&action=example_proxy&url=http://127.0.0.1/server-statusAnd there it was. The full internal Apache status page โ live requests and all โ rendered right back to me through the SSRF. ๐คฏ
That is the exact moment a Medium-severity SSRF grows up, gets a job, and becomes a Critical. I now had a live window into the server's internal activity, a proven way to enumerate internal services, and a clear path to reach resources that were never, ever meant to see daylight. ๐
Why This Actually Matters (the "so what" bit) ๐
Let's zoom out on everything this one little url= parameter quietly handed over:
- ๐ Arbitrary external requests โ the server fetches any URL you feed it
- ๐ Internal service access โ
localhostand internal-only services become reachable - ๐ Internal port enumeration โ open vs. closed ports respond differently, so the internal network becomes mappable
- ๐ก Sensitive info disclosure โ the exposed
/server-statuspage leaked live internal request data
In the wrong hands, an SSRF like this is a launchpad โ for hitting cloud metadata endpoints, pivoting to internal admin panels, or chaining into something even nastier. It's the classic "looks small until you realize the entire internal network was standing right behind it" bug. ๐ช๐
The Fix (for the blue team reading this) ๐ก๏ธ
If you're maintaining a proxy-style endpoint, here's how you stop your intern from running errands for strangers:
- โ Allowlist, don't blocklist. Only permit the specific external domains the feature actually needs. Everything else gets a firm, polite "no."
- ๐ซ Block internal ranges. Reject
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16, and169.254.169.254(hello there, cloud metadata) โ after resolving DNS, not before. - ๐งญ Validate the resolved IP, not just the string. Attackers adore DNS rebinding and sneaky redirect tricks. Check where the URL actually lands.
- ๐ฏ Ask if you even need a proxy at all. Half the time the safest SSRF fix is a hard look in the mirror and "โฆwhy does this endpoint exist?"
Wrapping Up ๐
And that's the tale of the proxy that trusted everyone. It started as a single suspicious parameter that HackLens surfaced during recon, snowballed into internal network access, and ended as a Critical thanks to one exposed status page and one gloriously intrusive thought. ๐ง โจ
Moral of the story: never trust user input, never trust a url= parameter, and definitely never let your server become someone else's errand boy. ๐โโ๏ธ
๐ ๏ธ The Tool Behind This Hunt
Since folks always ask โ yep, HackLens is my own tool, it's open source, it's free, and it's the reason this endpoint ever crossed my radar.
๐ฆ HackLens โ automated recon & vuln scanning from your terminal
๐ github.com/yogeshbhandage/hacklens
Point it at a domain and it runs the entire pipeline end-to-end so you don't have to babysit ten different tools:
- ๐ Subdomain enumeration โ 10+ sources (crt.sh, Subfinder, Amass, Assetfinder & friends)
- ๐ Alive checks with httpx
- ๐ธ๏ธ JS & URL collection โ this is the stage that surfaced this very endpoint
- ๐ Secret scanning โ 240+ patterns (AWS, Stripe, JWTs, OAuth, DB URIs, you name it)
- ๐ฏ Reflected XSS โ 3-phase, context-aware, ready-to-use PoC URLs
- โช๏ธ Open redirect โ 3-layer detection with bypass probes
- ๐๏ธ Information disclosure โ 70+ probe paths (actuators,
.git,.env, stack traces & more)
When it's done, it hands you a clean JSON report plus a visual HTML report you can review and submit. One command:
bash run.sh -d example.com --deep --subsbash run.sh -d example.com --deep --subsIt can also chew through a pre-crawled URL list (-l urls.txt) or a full Burp Suite XML export (-b burp_export.xml) if you've already got traffic to feed it.
๐งฉ HackLens for Burp โ the passive watcher
๐ github.com/yogeshbhandage/burp_hacklens
And if you live inside Burp like the rest of us, there's a companion extension too. HackLens for Burp is a Burp Suite scanner that quietly watches your traffic and flags interesting stuff while you browse like a normal human being โ no loud active scans, no noise, just a chill little extension in the background going "psst, you might wanna look at this." ๐ Perfect for manual testing where you want a second pair of eyes on everything flowing through Burp.
Stars โญ, forks ๐ด, and PRs are always appreciated on both. If you build something cool on top of them, I'd genuinely love to hear about it.
Thanks for reading, folks! If you enjoyed this one, drop a clap ๐ and I'll catch you in the next write-up. Happy (and ethical) hacking! ๐๐จ
Disclaimer: This was found and reported responsibly through proper disclosure channels. All identifying details have been redacted. Only test systems you're authorized to test. Stay legal, stay curious. ๐ค