본문 바로가기

DreamHack

[DreamHack] funjs

https://dreamhack.io/wargame/challenges/116

 

funjs

Description 입력 폼에 데이터를 입력하여 맞으면 플래그, 틀리면 NOP !을 출력하는 HTML 페이지입니다. main 함수를 분석하여 올바른 입력 값을 찾아보세요 !

dreamhack.io

난이도: Level 2

index.html

<html>
    <head>
    <style>*{margin: 0;}</style>
    <script>
    var box;
    window.onload = init;
    function init() {
      box = document.getElementById("formbox");
      setInterval(moveBox,1000);
    }
    function moveBox() {
        box.posX = Math.random() * (window.innerWidth - 64); 
        box.posY = Math.random() * (document.documentElement.scrollHeight - 64); 
        box.style.marginLeft = box.posX + "px";
        box.style.marginTop  = box.posY + "px";
        debugger;
    }

    function text2img(text){
        var imglist = box.getElementsByTagName('img');
        while(imglist.length > 0) {imglist[0].remove();}
        var canvas = document.createElement("canvas");
        canvas.width = 620;
        canvas.height = 80;
        var ctx = canvas.getContext('2d');
        ctx.font = "30px Arial";
        var text = text;
        ctx.fillText(text,10,50);
        var img = document.createElement("img");
        img.src = canvas.toDataURL();
        box.append(img);
    };

    function main(){
        var _0x1046=['2XStRDS','1388249ruyIdZ','length','23461saqTxt','9966Ahatiq','1824773xMtSgK','1918853csBQfH','175TzWLTY','flag','getElementById','94hQzdTH','NOP\x20!','11sVVyAj','37594TRDRWW','charCodeAt','296569AQCpHt','fromCharCode','1aqTvAU'];
        var _0x376c = function(_0xed94a5, _0xba8f0f) {
            _0xed94a5 = _0xed94a5 - 0x175;
            var _0x1046bc = _0x1046[_0xed94a5];
            return _0x1046bc;
        };
        var _0x374fd6 = _0x376c;
        (function(_0x24638d, _0x413a92) {
            var _0x138062 = _0x376c;
            while (!![]) {
                try {
                    var _0x41a76b = -parseInt(_0x138062(0x17f)) + parseInt(_0x138062(0x180)) * -parseInt(_0x138062(0x179)) + -parseInt(_0x138062(0x181)) * -parseInt(_0x138062(0x17e)) + -parseInt(_0x138062(0x17b)) + -parseInt(_0x138062(0x177)) * -parseInt(_0x138062(0x17a)) + -parseInt(_0x138062(0x17d)) * -parseInt(_0x138062(0x186)) + -parseInt(_0x138062(0x175)) * -parseInt(_0x138062(0x184));
                    if (_0x41a76b === _0x413a92) break;
                    else _0x24638d['push'](_0x24638d['shift']());
                } catch (_0x114389) {
                    _0x24638d['push'](_0x24638d['shift']());
                }
            }
        }(_0x1046, 0xf3764));
        var flag = document[_0x374fd6(0x183)](_0x374fd6(0x182))['value'],
            _0x4949 = [0x20, 0x5e, 0x7b, 0xd2, 0x59, 0xb1, 0x34, 0x72, 0x1b, 0x69, 0x61, 0x3c, 0x11, 0x35, 0x65, 0x80, 0x9, 0x9d, 0x9, 0x3d, 0x22, 0x7b, 0x1, 0x9d, 0x59, 0xaa, 0x2, 0x6a, 0x53, 0xa7, 0xb, 0xcd, 0x25, 0xdf, 0x1, 0x9c],
            _0x42931 = [0x24, 0x16, 0x1, 0xb1, 0xd, 0x4d, 0x1, 0x13, 0x1c, 0x32, 0x1, 0xc, 0x20, 0x2, 0x1, 0xe1, 0x2d, 0x6c, 0x6, 0x59, 0x11, 0x17, 0x35, 0xfe, 0xa, 0x7a, 0x32, 0xe, 0x13, 0x6f, 0x5, 0xae, 0xc, 0x7a, 0x61, 0xe1],
            operator = [(_0x3a6862, _0x4b2b8f) => {
                return _0x3a6862 + _0x4b2b8f;
            }, (_0xa50264, _0x1fa25c) => {
                return _0xa50264 - _0x1fa25c;
            }, (_0x3d7732, _0x48e1e0) => {
                return _0x3d7732 * _0x48e1e0;
            }, (_0x32aa3b, _0x53e3ec) => {
                return _0x32aa3b ^ _0x53e3ec;
            }],
            getchar = String[_0x374fd6(0x178)];
        if (flag[_0x374fd6(0x17c)] != 0x24) {
            text2img(_0x374fd6(0x185));
            return;
        }
        for (var i = 0x0; i < flag[_0x374fd6(0x17c)]; i++) {
            if (flag[_0x374fd6(0x176)](i) == operator[i % operator[_0x374fd6(0x17c)]](_0x4949[i], _0x42931[i])) {} else {
                text2img(_0x374fd6(0x185));
                return;
            }
        }
        text2img(flag);
    }
    </script>
    </head>
    <body>
        <div id='formbox'>
            <h2>Find FLAG !</h2>
            <input type='flag' id='flag' value=''>
            <input type='button' value='submit' onclick='main()'>
        </div>
    </body>
</html>

변수명과 함수명이 임의의 값으로 설정되어 있어 코드를 해석하기 어렵기 때문에, 알아보기 쉽게 변수명과 함수명을 수정해 줍니다.   

 

이후, flag 변수 이전까지의 코드를 돌리고 나면, 여러 중요 키워드들을 얻을 수 있습니다. 

이것을 하면서 실수했었던 점이 func2 밑에 함수를 실행시켜보지 않고, func2(0x183) 값을 손으로 직접 구하다보니 이상한 키워드들이 나와서 삽질을 했었습니다...

 

function main(){
    ...
    // document['getElementById']('flag')['value']
    var flag = document[func2(0x183)](func2(0x182))['value'],
        arr1 = [0x20, 0x5e, 0x7b, 0xd2, 0x59, 0xb1, 0x34, 0x72, 0x1b, 0x69, 0x61, 0x3c, 0x11, 0x35, 0x65, 0x80, 0x9, 0x9d, 0x9, 0x3d, 0x22, 0x7b, 0x1, 0x9d, 0x59, 0xaa, 0x2, 0x6a, 0x53, 0xa7, 0xb, 0xcd, 0x25, 0xdf, 0x1, 0x9c],
        arr2 = [0x24, 0x16, 0x1, 0xb1, 0xd, 0x4d, 0x1, 0x13, 0x1c, 0x32, 0x1, 0xc, 0x20, 0x2, 0x1, 0xe1, 0x2d, 0x6c, 0x6, 0x59, 0x11, 0x17, 0x35, 0xfe, 0xa, 0x7a, 0x32, 0xe, 0x13, 0x6f, 0x5, 0xae, 0xc, 0x7a, 0x61, 0xe1],
        operator = [(_0x3a6862, _0x4b2b8f) => {
            return _0x3a6862 + _0x4b2b8f;
        }, (_0xa50264, _0x1fa25c) => {
            return _0xa50264 - _0x1fa25c;
        }, (_0x3d7732, _0x48e1e0) => {
            return _0x3d7732 * _0x48e1e0;
        }, (_0x32aa3b, _0x53e3ec) => {
            return _0x32aa3b ^ _0x53e3ec;
        }],
        getchar = String[func2(0x178)];
    // flag['length'] != 0x24
    if (flag[func2(0x17c)] != 0x24) {
        text2img(func2(0x185));
        return;
    }
    // flag[func2(0x17c)] == flag['length']
    for (var i = 0x0; i < flag[func2(0x17c)]; i++) {
        // flag['charCodeAt'](i) == operator[i % operator.length](arr1[i], arr2[i])
        if (flag[func2(0x176)](i) == operator[i % operator[func2(0x17c)]](arr1[i], arr2[i])) {} else {
            text2img(func2(0x185));
            return;
        }
    }
    text2img(flag);
}

위에서 얻은 중요한 키워드들을 적어놓고 나면, arr1과 arr2가 flag 길이 만큼 +, -, *, ^ 연산을 반복하며 나온 각각의 값이 flag['charCodeAt'](i)와 동일한지를 확인하고 있다는 것을 알 수 있습니다. 

 

결과 확인을 위해 arr1과 arr2 배열을 선언한 후, operator 또한 선언해줍니다. 

이후, console.log를 통해 연산 결과를 출력해줍니다. 

flag.length가 0x24가 아니면 return 하는 if 문이 for 앞에 있었기 때문에 for문에서 0x24만큼 반복하여 코드를 실행하였고, 실행 결과 값이 잘 나오는 것을 확인할 수 있습니다. 

 

이후, charCodeAt의 역순인 fromCharCode를 사용하면 FLAG를 획득할 수 있습니다. 

'DreamHack' 카테고리의 다른 글

[DreamHack] Client Side Template Injection  (2) 2023.09.04
[DreamHack] Tomcat Manager  (2) 2023.09.04
[DreamHack] weblog-1  (2) 2023.09.01
[DreamHack] DOM XSS  (0) 2023.09.01
[DreamHack] CSS Injection  (2) 2023.08.31