DropCall
Wilderness Permits' search was rebuilt in 2023 with a deliberately minimal failure surface. Minimal is not the same as silent.
The Scenario
Wilderness Permits Inc. runs a federal contractor reservation system on
Postgres. The permit search was rebuilt in 2023; the previous design
had been criticised in a vendor security review for showing too much of
the query structure to API scrapers, so the platform team locked the
failure path down to a generic "search unavailable" page. The admin
console configuration shares the database, because everything Wilderness
Permits runs sits on the same RDS instance — they're a twelve-person
shop and a second database would mean a second on-call rotation.
Challenge Intel
Synopsis
Wilderness Permits' search returns 500 when the SQL fails and 200 when it succeeds. Use the status-code difference as a boolean oracle (CASE WHEN with a row-context divide-by-zero in the ELSE) to extract the admin token character by character.
What It Is
Wilderness Permits Inc. runs a federal contractor permit reservation system on Postgres. Their permit search splices the park parameter into a SELECT. SQL errors are not surfaced in the response body — the page returns a generic 500 with a "Search unavailable" message. Successful queries return 200, regardless of whether they have results. The lesson is blind error-based SQL injection using HTTP status as the oracle. The player crafts payloads using CASE WHEN to either succeed (return 200) or trigger a runtime error (return 500). Postgres-specific wrinkle: constant ELSE branches like `1/0` or `CAST('a' AS INTEGER)` get folded at planning time and fire unconditionally. Pin the divide-by-zero to a column reference (`1/(id-id)`) to keep the error in row-evaluation context. Extraction proceeds character-by-character using the status code.
Who It's For
Players moving past boolean-blind (page-content) into status-code-based blinds.
Skills You'll Practice
- Distinguishing 200-success-empty from 500-SQL-error
- Crafting CASE WHEN payloads that conditionally error
- Postgres planner quirks: constant-folding of CASE branches
- Postgres syntax (SUBSTR, CASE WHEN ... THEN ... ELSE ... END, integer division)
- Character-by-character extraction via status-code oracle
What You'll Gain
- Comfort with blind extraction when no body content varies
- Postgres SQLi muscle memory (vs MySQL/SQLite)
- Awareness of constant-folding traps in error-based payloads