본문 바로가기

드림핵

[드림핵 워게임] funjs

위의 문제를 아래와 같은 과정으로 풀어보았다.

 

 

1. 페이지의 기능을 확인한다.

드림핵 사이트에서 다운로드한 파일을 브라우저에서 실행하면 위와 같은 배너가 창을 마구 돌아다닌다.

 

 

입력창에 임의의 입력값 flag를 입력하면 잘못된 입력값이기 때문에 NOP!이라는 문구가 뜨는 것을 확인할 수 있다.

 

 

 

2. 코드를 확인한다.

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);

 

16진수로 쓰여 있어서 의미를 알아보기 어려우나 개발자 도구(F12)를 이용해서 의미를 찾아본다.

 

 

        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)];

main 함수의 변수 선언 부분이다. 이 부분을 복사해서 개발자 도구의 콘솔창에서 실행한다.

 

 

콘솔창에서 실행했다.

 

의미를 알 수 없는 16진수들을 콘솔창에 복사, 붙여넣기하여 값을 찍어보면 위와 같이 나온다. 이 출력값을 토대로 코드를 이해해보자.

 

 

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);

출력값을 토대로 코드를 다음과 같이 이해할 수 있다.

1) flag의 'length'36이 아니면 'NOP!'을 출력한다.

2) for문은 flag의 'length'만큼 반복된다.

3) flag의 i번째('charCodeAt') 문자가 operator[i % operator[length]](_0x4949[i], _0x42931[i])과

4) 다르면 'NOP!'을 출력한다.

5) 같으면 flag를 출력한다.

 

 

 

3. 익스플로잇 코드를 작성하여 플래그를 획득한다.

for문의 반복횟수를 flag의 length 즉, 36으로 하여 operator[i % operator[length]](_0x4949[i], _0x42931[i])와 일치하는 문자를 하나씩 가져와 flag를 완성하는 익스플로잇 코드를 짤 것이다.

 

 

var flagcode='';
for (i=0; i < 36; i++) {
	flagcode += String.fromCharCode(operator[i % operator[_0x374fd6(0x17c)]](_0x4949[i], _0x42931[i]));
}

익스플로잇 코드이다. fromCharCode() 함수는 아스키코드 번호를 받아 문자열을 구성해주는 함수이다.

(참고로 앞에 나온 charCodeAt 함수는 문자열 중 하나를 선택하여 아스키코드 번호로 변환해주는 함수이다.)

 

 

개발자도구의 콘솔창에서 익스플로잇 코드를 실행하여 flag를 획득한다.