portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Testing and Exploiting NoSQL Injection in MongoDB

Testing for NoSQL Injection

We can test the web application for NoSQL injections by entering fuzz strings as input. Example fuzz strings include:

'"`{;$Foo}$Foo \xYZ
'\"`{\r;$Foo}\n$Foo \\xYZ

If there is a change in the application response, we can determine which characters are interpreted as syntax by the application by injecting individual characters. For example, submitting ' may result in the following MongoDB query:

this.category == '''

Understanding NoSQL Injection in MongoDB

NoSQL injection is a vulnerability that allows attackers to manipulate queries sent to a NoSQL database, such as MongoDB, potentially leading to unauthorized access, data extraction, denial of service, or even remote code execution. This guide outlines how to detect and exploit NoSQL injection vulnerabilities in MongoDB.


Types of NoSQL Injection

  1. Syntax Injection: Attackers break the query syntax to inject malicious payloads, similar to SQL injection but adapted to NoSQL query languages and data structures.
  2. Operator Injection: Attackers manipulate queries using NoSQL-specific operators (e.g., $where, $ne, $in, $regex) to alter query logic or extract data.

Detecting Syntax Injection in MongoDB

Scenario

Consider a shopping application querying a MongoDB database for products in a category, such as:

https://insecure-website.com/product/lookup?category=fizzy

This translates to the MongoDB query:

this.category == 'fizzy'

Steps to Detect Syntax Injection

  1. Fuzz Testing:
    • Inject a fuzz string to test if user input is improperly sanitized. For MongoDB, use a string like:
      '"`{;$Foo}$Foo \xYZ
      
    • URL-encoded, this becomes:
      https://insecure-website.com/product/lookup?category='%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00
      
    • If the response changes (e.g., an error or different output), it may indicate unfiltered input.
  2. Testing Individual Characters:
    • Inject a single character, such as a single quote ('), to form:
      this.category == '''
      
    • If this causes a syntax error or response change, the input may be vulnerable.
    • Confirm by escaping the quote (e.g., \'') to check if the query executes normally:
      this.category == '\''
      
  3. Testing Conditional Behavior:
    • Send two requests to test boolean conditions:
      • False condition: ' && 0 && 'x
      • True condition: ' && 1 && 'x
    • If the responses differ, it suggests the application processes injected conditions, indicating a vulnerability.

Exploiting Syntax Injection

Warning: Injecting always-true conditions can affect multiple queries, potentially causing unintended data modifications or deletions.


Detecting and Exploiting Operator Injection in MongoDB

Scenario

Consider a login request with a JSON body:

{"username":"wiener","password":"peter"}

Detecting Operator Injection

  1. Test with Operators:
    • Inject a MongoDB operator like $ne:
      {"username":{"$ne":"invalid"},"password":"peter"}
      
    • If the response changes (e.g., logs in as another user), the application may process operators.
  2. Bypass Authentication:
    • Use:
      {"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}
      

      This queries all users where username and password are not “invalid,” potentially logging in as the first user in the collection.

    • To target specific accounts:
      {"username":{"$in":["admin","administrator","superadmin"]},"password":{"$ne":""}}
      
  3. Switch to JSON for URL-based Inputs:
    • If URL parameters (e.g., username[$ne]=invalid) fail, convert the request to POST with Content-Type: application/json and inject operators in the JSON body.

Exploiting Syntax Injection to Extract Data

Scenario

A user lookup request:

https://insecure-website.com/user/lookup?username=admin

This triggers:

{"$where":"this.username == 'admin'"}

Extracting Data with JavaScript

Identifying Field Names


Exploiting Operator Injection to Extract Data

Injecting Operators

Extracting Field Names

Extracting Data with $regex


Timing-Based NoSQL Injection

When error-based injection doesn’t yield response differences, use timing-based payloads to detect vulnerabilities:

  1. Measure Baseline:
    • Load the page multiple times to establish normal response time.
  2. Inject Timing Payload:
    • Example:
      {"$where":"sleep(5000)"}
      

      This delays the response by 5 seconds if executed.

    • For password extraction:
      admin'+function(x){var waitTill = new Date(new Date().getTime() + 5000);while((x.password[0]==="a") && waitTill > new Date()){};}(this)+'
      

      or

      admin'+function(x){if(x.password[0]==="a"){sleep(5000)};}(this)+'
      

      A delayed response indicates the password starts with ‘a’.

  3. Analyze Response Time:
    • A noticeable delay confirms successful injection.

Key Considerations