Platform: TryHackMe · Difficulty: Easy · Category: IDOR
Introduction
Neighbour is a box whose entire security model rests on the assumption that users won't look at the URL bar after logging in. It's a PHP web app with a login form, a profile page, and all the authorisation rigor of an honour system at an unmanned farm stall. The login page even helpfully leaves guest credentials in an HTML comment with a winking Ctrl+U hint. The developer wanted you to find it. What they perhaps didn't intend was for ?user=admin to work just as smoothly right afterwards.
Recon
Full-range scan with RustScan, detailed service fingerprinting via Nmap:
rustscan -a 10.49.169.236 -r 1-65535 --ulimit 5000 -- -Pn -sC -sV
| Port | Service | Version |
|---|---|---|
| 22/tcp | SSH | OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 |
| 80/tcp | HTTP | Apache httpd 2.4.53 (Debian) |
One detail worth flagging: the PHPSESSID cookie is missing the HttpOnly flag. A small note, but it confirms this is a PHP application and hints that session security wasn't a top priority here either.
Feroxbuster scanning with PHP, TXT, and HTML extensions:
feroxbuster -u http://10.49.169.236/ \
-w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt \
-x php,txt,html
# output (relevant hits only)
200 http://10.49.169.236/index.php
200 http://10.49.169.236/login.php
302 http://10.49.169.236/profile.php => login.php # ^^^ redirects unauthenticated users
301 http://10.49.169.236/db => /db/
200 http://10.49.169.236/db.php # ^^^ exists but returns empty body
302 http://10.49.169.236/logout.php => login.php
profile.php bounces unauthenticated visitors straight to login.php — so there is some kind of session check at the door. The question is whether that check extends to which user's profile you can view once you're inside. Spoiler: it doesn't.
db.php returns a blank response, which likely means it's a database connection include file rather than a standalone page.
The login page itself drops a hint in plain HTML: Ctrl+U is called out right in the UI. Taking the bait:
view-source:http://10.49.169.236/
<!-- use guest:guest credentials until registration is fixed. "admin" user account is off limits!!!!! -->
Guest credentials, giftwrapped in an HTML comment. The five exclamation marks on "off limits" are doing a lot of emotional heavy lifting for what is ultimately a URL parameter.
| Username | Password | Where Found |
|---|---|---|
guest |
guest |
HTML comment in index.php source |
Foothold
An Insecure Direct Object Reference occurs when an application uses a user-supplied value — a filename, a username, a numeric ID — to directly look up and return a resource, without checking whether the requesting user is actually authorised to access that specific resource. It's one of the most common and most impactful web vulnerabilities: the server trusts the client to only ask for things it's allowed to see, which is precisely the one thing a client should never be trusted to do.
After logging in with guest:guest, the application lands here:
http://10.49.169.236/profile.php?user=guest
Hi, guest. Welcome to our site. Try not to peep your neighbor's profile.
That message is either a warning or an instruction depending on your disposition. The ?user= parameter is server-side rendered — the PHP backend looks up whatever username value is passed and returns that profile. The question is whether it checks that the logged-in session matches the requested username.
Modifying the URL parameter directly in the browser address bar:
http://10.49.169.236/profile.php?user=admin
The server doesn't check. It just looks up admin and returns:
Hi, admin. Welcome to your site. The flag is: flag{66be95c478473d91a5358f2440c7af1f}
No re-authentication. No access control check. One URL edit.
Shell / Access
No shell required. The flag was delivered directly in the HTTP response body after the IDOR parameter manipulation.
Escalation
Not applicable — the challenge resolves entirely at the web layer with no system-level privilege escalation involved.
Exploitation — The Full Chain
-
HTML comment on the login page → guest credentials
guest:guest -
Login as
guest→ lands onprofile.php?user=guest -
IDOR identified —
?user=has no server-side ownership check -
URL edit to
?user=admin→ admin profile returned → flag delivered directly
Rabbit Holes
None encountered — the chain resolves cleanly in a handful of steps with no dead ends.
Flags
| Flag | Value | Location |
|---|---|---|
| Challenge Flag | flag{66be95c478473d91a5358f2440c7af1f} |
profile.php?user=admin response |
Mitigations
| Vulnerability | Severity | Mitigation |
|---|---|---|
IDOR on profile.php?user=
|
High | Validate server-side that the authenticated session user matches the requested profile; never trust user-supplied object references for access control |
| Guest credentials hardcoded in HTML comment | Medium | Remove all credentials from client-deliverable files; use environment variables or a proper user registration flow |
Missing HttpOnly flag on PHPSESSID
|
Low | Set session.cookie_httponly = 1 in php.ini to prevent JavaScript access to the session cookie |
Key Takeaway
A session cookie proves you're logged in — it doesn't automatically prove you're allowed to access every resource on the server. Always verify server-side that the authenticated user owns or has permission to access the specific object being requested, not just that they're authenticated at all.
Room: TryHackMe — Neighbour
Top comments (0)