본문 바로가기

WEB

javascript proto pollution

공부중입니다... 

What is prototype

 

자바스크립트는 객체지향 언어이지만 C++이나 JAVA와 같은 class가 없다. 대신 protoype이라는 개념이 등장한다.(prototype에 대해서 잘 설명한 글의 링크가 밑에 있다. 따라서 자세한 개념 설명보다는 prototype pollution에 필요한 내용 위주로 설명겠다.) class 개념이 없기 때문에 자바스크립트에서 객체를 생성할 때는 함수와 new 키워드를 이용한다.

var test = function(a,b,c){
    this.a=a;
    this.b=b;
    this.c=c;
}
a = new test(1,2,3)
b = new test(4,5,6)
a.dd=1;
b.dd=1;

이때 a와 b 객체는 {"dd":1}라는 공통적인 요소를 가지고 있다. 하지만 a와 b에 dd라는 요소를 새로 생성하여 넣기 때문에 메모리를 두 배로 사용하게 된다. 또한 a.test를 수정해도 b.test는 변하지 않는다. 

만약 a.dd와 b.dd에 같은 객체를 넣고 싶다면 prototype을 사용해야 한다. 아래와 같은 방법을 사용하면 a.dd와 b.dd에 같은 객체가 들어간다. 

var test = function(a,b,c){
    this.a=a;
    this.b=b;
    this.c=c;
}
a = new test(1,2,3)
b = new test(4,5,6)
a.__proto__.dd=1;
console.log(b.dd)

a.__proto__.dd에만 값을 넣고 b는 건들이지 않았는데, b.dd에 값이 들어간 것을 확인할 수 있다. 

뿐만 아니라 앞으로 새로 생성하는 요소들에도 dd가 들어있는 것을 확인할 수 있다. 

 

var test = function(a,b,c){
    this.a=a;
    this.b=b;
    this.c=c;
}
a = new test(1,2,3)
b = new test(4,5,6)
a.__proto__.dd=1;
c= new test(1,2,3)
console.log(c.dd)

 

 

 

이는 자바스크립트의 객체에서 어떤 속성을 찾기 위해서 그 객체 뿐만 아니라 그 객체의 prototype까지 쭉 거슬러 올라가서 속성을 찾기 때문이다.


What is prototype pollution

 

prototype pollution이란 prototype의 특성을 이용하여 다른 객체의 값을 오염시키는 공격 기법이다. 

 

자바스크립트는 프론트엔드를 만들기 위해서 많이 사용되지만 nodeJs를 이용하여 자바스크립트로 서버를 구성할 수도 있다. prototype pollution의 예제로 아래와 같은 코드를 만들었다. 

 

admin페이지에 접속하면 admin에 있는 모든 속성 대하여 password를 가져온 후 유저가 보낸 passowrd의 값과 비교한다. 일치하는 것이 있는 경우 flag를 뿌려준다. 이 경우 서버에 존재하는 "superSecretPassword"값이 노출되지 않는한 flag값은 노출되지 않을 것이다.

 

groupadd는 중요한 부분이 아니니 넘어가자.

 

register페이지에 접근하면 users[req.body.group][req.body.id]=req.body.password;을 통하여 회원을 생성한다. 

'use strict';
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = 8080


let admin={"admin":"superSecretPassword"}//admin 내에서도 권한 구분?
let users={}
app.use(express.json())
app.post("/admin", function(req,res){
	for(var id in admin){
		if(admin[id]==req.body.password){
			res.send("flag{flag_is_flag}")
		}

	}
	res.send("You are not admin")
}
)

app.post("/register", function(req,res){
	users[req.body.group][req.body.id]=req.body.password;
	res.send("register OK!!")
})

app.post("/groupadd", function(req,res){
	users[req.body.group]={};
	res.send(req.body.group+"group add")
})

app.listen(port, () => console.log(`simple login system`))

register 페이지에서 prototype pollution 취약점이 발생한다. 

users[req.body.group][req.body.id]=req.body.password;

만약 유저가 register 페이지에 아래와 같은 페이로드를 보낸다고 생각해보자.

  • group="__proto__"
  • id = "JJY"
  • password = "JJY"

이 경우 서버에서 실행되는 코드는 다음과 같다. users의 prototype 즉 dictionary에 {"JJY":"JJY"} 속성이 추가된다. 이때 admin 역시 dictionary로 생성된 객체이기 때문에 admin.JJY을 열람할 경우 "JJY"가 리턴된다. 

users["__proto__"]["JJY"]="JJY";

따라서 유저가 admin 페이지에 아래의 페이로드를 전송한다고 생각해보자.

  • password = "JJY"

그러면 반복문을 도는 중 아래와 같은 식이 True를 반환하여 flag가 출력된다.

 

admin["JJY"]=="JJY"

 

 

 


advanced

 

1. JS pollution to RCE

RCE라는 측면에서 가치가 높은데 조건이 까다롭다.

https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/

 

2. Object

자바스크립트의 모든 객체에 대하여 prototype을 쭉 오르다보면 Object라는 객체에 도달한다. 따라서 해당 객체가 오염될 경우 자바스크립트에서 사용하는 모든 객체들이 오염된 값을 참조하게 된다.  

 

a=[]//a.__proto__'s proto = Object
a['__proto__']["__proto__"]["test"]=["test"] //set Object.__proto__['test']='test'

3. prototype pollution이 발생하는 다양한 케이스 

 

취약점이 발생하는 3가지 케이스 (예제 코드에서 빼먹은 부분이 있어서 그대로 실행이 안 된다.) 두번째 링크에 온전한 코드가 있다.

https://blog.coderifleman.com/2019/07/19/prototype-pollution-attacks-in-nodejs/ 

https://blog.0daylabs.com/2019/02/15/prototype-pollution-javascript/


prototype에 대하여 잘 설명한 글

https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67

 

 

 

 

 

 

 

'WEB' 카테고리의 다른 글

Relative Path Overwrite  (0) 2020.09.15
Redpwn CTF 2020 / post-it-notes  (0) 2020.06.23
Web cache deception attack  (0) 2020.05.27
SOP, CORS, CSP  (0) 2020.04.21