보안/Web hacking

[Dreamhack] Fly me to the moon

melonbbang-ruffy 2025. 1. 20. 13:50

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

 

[wargame.kr] fly me to the moon

Description javascript game. can you clear with bypass prevent cheating system?

dreamhack.io

서버 코드가 따로 주어지지 않은 문제다. 게임 사이트인가? 

웹 사이트에 접속해보자.

갤러그인가? 한번 실행해보자.

시작하자마자 바로 죽었다. 점수를 31337점을 따야 한다고 나온다.

물론 게임을 주구장창해서 31337점을 얻고 플래그를 얻어내는 방법도 있겠지만, 개발자 도구 콘솔을 이용해서 점수를 조작한 뒤 플래그를 얻어볼 생각이다.

Do cheating. If you can

왠지 킹받는 문구다.

-> VM7:1 이 코드를 살펴보자

웹 사이트의 자바스크립트 코드가 보인다.

여기서 중요한 코드는 뭐가 있는지 살펴보자.

updateTunnel 부분을 보자.

해당 함수는

 

  • 배경 및 터널 상태 업데이트 (bg_val 값 조정, 벽 위치 갱신)
  • 플레이어의 위치 업데이트 (ship_x의 위치 조정)
  • 점수 업데이트 (BTunnelGame.BincScore() 호출로 점수 증가)
  • 종료 조건 검사 (killPlayer() 호출)
  • 점수 및 상태 업데이트 결과를 UI에 반영

등의 기능을 하고 있는데, 게임을 조작하다보면 시간이 흐를수록 자동으로 점수가 올라가는 것을 발견할 수 있다.

점수 업뎃 부분으로 가 보자

 

BTunnelGame.BinScore() 함수는 점수 변경에 관여하는 핵심 함수로, c_s의 값이 20이 넘을 때마다(즉 타이머 값이 20이 넘을 때마다) 해당 함수를 호출해서 점수를 증가시키고 있다. 이 함수에 bp를 걸고 게임을 실행시켜보자.

 

 

Exploit

이 부분을 살펴보자.

var _0x32bb = ["\x6B\x69\x6C\x6C\x50\x6C\x61\x79\x65\x72", "\x63\x68\x65\x63\x6B\x4C\x69\x66\x65", "\x67\x65\x74\x53\x63\x6F\x72\x65", "\x42\x69\x6E\x63\x53\x63\x6F\x72\x65", "\x73\x68\x72\x69\x6E\x6B\x54\x75\x6E\x6E\x65\x6C", "\x77\x69\x64\x74\x68\x54\x75\x6E\x6E\x65\x6C", "\x6F\x62\x6A\x65\x63\x74", "\x44\x6F\x20\x63\x68\x65\x61\x74\x69\x6E\x67\x2C\x20\x69\x66\x20\x79\x6F\x75\x20\x63\x61\x6E", "\x77\x61\x72\x6E", "\x6F\x66\x66\x73\x65\x74\x4C\x65\x66\x74", "\x74\x75\x6E\x6E\x65\x6C", "\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64", "\x74\x6F\x70", "", "\x70\x78", "\x63\x73\x73", "\x64\x69\x73\x70\x6C\x61\x79", "\x62\x6C\x6F\x63\x6B", "\x65\x61\x63\x68", "\x69\x6D\x67\x2E\x6C\x65\x66\x74\x5F\x77\x61\x6C\x6C", "\x69\x6D\x67\x2E\x72\x69\x67\x68\x74\x5F\x77\x61\x6C\x6C", "\x23\x68\x69\x67\x68\x5F\x73\x63\x6F\x72\x65\x73", "\x72\x65\x6D\x6F\x76\x65", "\x74\x61\x62\x6C\x65", "\x6E\x6F\x6E\x65", "\x64\x69\x76\x23\x73\x63\x6F\x72\x65\x5F\x74\x61\x62\x6C\x65", "\x63\x6C\x69\x63\x6B", "\x74\x65\x78\x74", "\x73\x70\x61\x6E\x23\x73\x63\x6F\x72\x65", "\x6C\x65\x66\x74", "\x69\x6D\x67\x23\x73\x68\x69\x70", "\x73\x6C\x6F\x77", "\x66\x61\x64\x65\x49\x6E", "\x62\x61\x63\x6B\x67\x72\x6F\x75\x6E\x64\x2D\x70\x6F\x73\x69\x74\x69\x6F\x6E", "\x35\x30\x25\x20", "\x64\x69\x76\x23\x74\x75\x6E\x6E\x65\x6C", "\x72\x61\x6E\x64\x6F\x6D", "\x66\x6C\x6F\x6F\x72", "\x75\x70\x64\x61\x74\x65\x54\x75\x6E\x6E\x65\x6C\x28\x29", "\x66\x61\x64\x65\x4F\x75\x74", "\x50\x4F\x53\x54", "\x68\x69\x67\x68\x2D\x73\x63\x6F\x72\x65\x73\x2E\x70\x68\x70", "\x74\x6F\x6B\x65\x6E\x3D", "\x26\x73\x63\x6F\x72\x65\x3D", "\x61\x6A\x61\x78", "\x68\x74\x6D\x6C", "\x70\x23\x77\x65\x6C\x63\x6F\x6D\x65", "\x75\x70\x64\x61\x74\x65\x54\x6F\x6B\x65\x6E\x28\x29", "\x74\x68\x78\x2C\x20\x43\x68\x72\x69\x73\x74\x69\x61\x6E\x20\x4D\x6F\x6E\x74\x6F\x79\x61", "\x6D\x6F\x75\x73\x65\x6F\x76\x65\x72", "\x23\x63\x68\x72\x69\x73\x74\x69\x61\x6E", "\x6D\x6F\x75\x73\x65\x6F\x75\x74", "\x72\x65\x61\x64\x79", "\x43\x68\x72\x69\x73\x74\x69\x61\x6E\x20\x4D\x6F\x6E\x74\x6F\x79\x61", "\x70\x61\x67\x65\x58", "\x6D\x6F\x75\x73\x65\x6D\x6F\x76\x65", "\x74\x6F\x6B\x65\x6E\x2E\x70\x68\x70", "\x67\x65\x74"];

난독화가 되어있다. 

BinScore() 함수 아래에 해당 배열의 두번째 부분을 불러내는 부분이 있는데, 이 부분을 복호화하면,

\x67\x65\x74\x53\x63\x6F\x72\x65

아스키코드 -> 문자로 변환

위의 결과로 'getScore'라는 문자열이 나온다.

즉 아래와 같은 코드는

BTunnelGame[_0x32bb[2]]();

BTunnelGame.getScore();로 해석된다.

의미만 봐서 알듯이, 점수 획득과 관련된 부분으로 생각되어진다.

해당 메소드를 재정의(점수 = 31337로 정의)해보자.

BTunnelGame.getScore = function() {
    return 31337; 
};

게임을 실행시켜보자. 아까 bp를 걸어놓은 부분에 중간에 멈춘 것을 확인할 수 있다.

 

콘솔에 위 코드를 입력하고 다시 실행시켜보자.

 

명심해야 할 건 한번 더 bp에 걸린 후 다시 실행해야 플래그가 출력된다. 안 그러면 cheating에 걸린다...

플래그 출력