July 31, 2026
Corridor: Twelve Doors, One IDOR
Corridor is a small room, and it doesn’t pretend otherwise. You land on a single page: a hallway lined with doors, nothing else to click…

By Enryuuu
4 min read
Corridor is a small room, and it doesn't pretend otherwise. You land on a single page: a hallway lined with doors, nothing else to click, nothing to explore beyond it. Every door looks the same, and every door does the same thing when you open it, drops you into an empty white room and nothing more.
That's the whole interface. But the interesting part was never the hallway itself, it was what the page was quietly asking the browser to fetch behind the scenes.
I'm writing this one because IDOR is a bug that shows up outside of CTFs constantly, and Corridor is about as clean an example of it as I've come across. One page, one flaw, no distractions.
Phase 1: Looking at the Doors
The corridor page loads with thirteen doors, each one clickable.
Clicking any of them sends the browser to a new URL and a blank room. Same layout, same nothing, no matter which door I picked. On its own that's not much to go on. Whatever was interesting about this room wasn't in what rendered on screen.
So instead of clicking through a fourteenth door, I pulled up the page source.
Phase 2: Reading the Source
The corridor's front page turned out to be an HTML image map. One image, with a set of clickable area regions layered over each door, and every one of those regions carried its own href. Instead of something like /room?id=3, each door pointed to a 32-character string that looked exactly like a hash.
Corridor doesn't make you guess at that part. The room's own briefing tells you outright that the values you'll find look like a hash specifically, an MD5 hash. That's a deliberate hint, not something I had to work out on my own, and it saved a step.
Phase 3: Cracking the Doors
I pulled all thirteen hashes out of the page source, dropped them into a single file, and ran them through John the Ripper against a common wordlist:
All thirteen cracked in under a second. The plaintext behind every hash was just a number (1 through 13), matching the count of doors in the hallway one-to-one. Each door's "hidden" identifier was nothing more than MD5(door_number).
Security Issue #1: Sequential IDs Hashed for Obfuscation, Not Protection. Running a value through MD5 doesn't make it unguessable, it just makes it look unguessable. Once an attacker recognizes the pattern, cracking every ID back to plaintext is a matter of seconds with a wordlist, not a meaningful barrier at all.
Phase 4: Testing the Edge
Thirteen doors, numbered one through thirteen. The obvious next question was what happens at zero. Nothing in the hallway linked to it, no door pointed there, but the endpoint itself never said it only accepted 1 through 13. It just said it wanted an MD5 hash.
So I hashed 0 myself. Burp's Decoder handled that in one step.
strip the whitespace it adds, and force it to lowercase, since the app was clearly matching on lowercase hex:
cfcd208495d565ef66e7dff9f98764da
Flag
Dropped that into the URL in place of one of the existing door hashes, and the response wasn't another blank room. It was the flag.
With the flag on screen, that's the room done. No privilege escalation, no lateral movement. Corridor is built to prove one point and stop, and it does that in about the time it takes to run a wordlist.
Security Issue #2: No Ownership or Range Check on the Object Reference. The server treated "is this a valid MD5 string" as good enough to serve a page. It never asked whether that particular ID was one the current visitor was meant to reach, or whether it fell inside the range of doors that were supposed to exist at all. An ID that was never linked from the UI was still fully reachable, because nothing on the server side actually gated it.
Blue Team Perspective
Working back through the chain, here's where I think a defensive team would have had a real chance to catch this, and what I'd fix.
1. Predictable, Sequential Identifiers.
Hashing door_number with an unsalted, general-purpose algorithm like MD5 doesn't add real entropy it's reversible with any common wordlist. Fix: use non-sequential, high-entropy identifiers (such as a UUIDv4) for anything referenced directly in a URL, and never treat hashing alone as an access control measure
2. Missing Authorization Check Per Request.
The application answered any syntactically valid ID without confirming the requester should be able to reach it. Fix: every object lookup should include an authorization check tied to the session, not just a lookup-and-serve.
3. Trusting "Not Linked" as "Not Reachable."
Door 0 was never shown in the UI, but it was live and fully served the moment someone asked for it correctly. Fix: don't rely on hiding a link as access control; anything the server will respond to needs an explicit check, whether or not the front end ever points to it.
This write-up is part of my ongoing series documenting CTF challenges as I build my portfolio in cybersecurity. I approach each challenge from both offensive and defensive perspectives, because understanding both sides is what makes a well-rounded security professional.
If you're also on the journey toward a SOC or Security Engineering role, feel free to connect — I'm always happy to discuss techniques and share resources.