GYCTF2020-Ez_Express
本文最后更新于:2024年12月14日 下午
从这个题学到不少东西,记录一下。
初识原型链
首先这题是有个原型链污染,js中每个类都有个属性__proto__
,指向他的基类,他会继承__proto
所拥有的特性。
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain)。
在js中,当我们调用一个对象的一个属性时,会首先在对象自身寻找这一属性,如果自身找不到则会寻找__proto__
,找不到就继续往上找,以此类推。
哪些情况下原型链会被污染
在含有能够控制数组(对象)的“键名”的操作即可,一般是以出现:
merge和clone对象不安全的对象递归合并
以merge,因为merge执行的就是递归,为例,先构造一个简单的merge函数
js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const merge = (target, source) => {
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
for (const key of Object.keys(source)) {
if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key]))
}
// Join `target` and modified `source`
Object.assign(target || {}, source)
return target
}
function Person(name,age,gender){//构造一个person类
this.name=name;
this.age=age;
this.gender=gender;
}
let newperson=new Person("test1",22,"male");
let job=JSON.parse('{"title":"Security Engineer","country":"China","__proto__":{"x":1}}');//新建一个job对象
merge(newperson,job);//这个job对象有用title、contry、__proto__属性,并对其进行赋值
console.log(newperson);
console.log(Person.prototype);//此时per的原型已经被改变为x=1这里解释一下,merge将这几个键值作为一个属性合并到newperson这个对象中了,merge函数执行的其实可以认为是
1
2
Person.job.title=......
Person.job.__proto__=....这个时候job的原型是Person,所以Person的值就发生了改变。
按路径定义属性
有些JavaScript库的函数支持根据指定的路径修改或定义对象的属性值。通常这些函数类似以下的形式:theFunction(object, path, value),将对象object的指定路径path上的属性值修改为value。如果攻击者可以控制路径path的值,那么将路径设置为_proto_.theValue,运行theFunction函数之后就有可能将theValue属性注入到object的原型中。
审计代码
这个题有个www.zip
,下载下来是有源代码的,进行审计。
主要的逻辑如下
1 |
|
一般ctf中的原型链污染会出现在merge
,clone
一类的函数中,这里看到有merge函数,clone又对它封装了一层,最后唯一调用clone的是/action
路由,但是这里要求管理员登录,所以先研究一下登录。
他要求admin登录但是过滤了admin,这里可以用上p神博客的一个小trick。
“ı”.toUpperCase() == ‘I’,”ſ”.toUpperCase() == ‘S’
“K”.toLowerCase() == ‘k’
js太神辣🥵
登录解决了
在action路由我们可以通过上传json让其解析为键值对达成控制runtime。
再来看info路由,这里调用了个没有定义的outputFunctionName
,可以污染outputFunctionName来rce,具体的原理得分析一下ejs的渲染。
ejs渲染分析
主要是探究一下render函数后面到底发生了什么
—-12.17更—-
时间拖太久了懒得再调一次了,总之就是ejs里面有一坨字符串拼接会把outputFunctionName
拼进去直接中断渲染提前return造成代码执行。当然这里的outputFunctionName
是由我们的原型链污染来控制的,在我们有原型链污染的前提之下,我们可以控制基类的成员。