본문 바로가기

Games/CTF

HDCON 2013 level4

윈도우 바이너리 문제이다.


장안의 화제가 되고 있는 게임인 ‘전설 전설 리그!’를 만든 게임 회사에 근무하는 손 오공(23세, 남)씨는 게임의 새로운 캐릭터의 디자인을 담당하는 직책과 더불어 고객센터에서 유저들과 상담하는 역할을 맡고 있다.


최근 유난히 많은 유저들이 게임에 접속하는 바람에 한동안 게임 서버가 정상적으로 동작하지 않아 많은 유저들의 원성을 샀기에, 고객센터에서 운영에 불만을 표출하는 유저들과 상담한다고 최근 오공 씨는 많은 스트레스를 받고 있다.


그런 어느 날, 서버 점검에 의해 자기 계정의 모든 캐릭터들이 사라졌다는 문의를 받게 되었고, 해당 문의의 첨부 파일로 계정의 현 상태를 캡쳐한 스크린샷이 있었다.

이를 확인하고 며칠 뒤, 오공 씨는 오랫동안 자신이 고안해온 캐릭터의 컨셉 디자인 그림 파일이 망가졌다는 사실을 알게 되었다. 왜 망가졌는지를 알기 위해 자신의 컴퓨터를 수 차례 확인한 오공 씨는 자신의 컴퓨터가 랜섬웨어에 감염되었다는 사실을 알게 되었다. 경찰에 신고해서 사이버 수사를 거친다면 범인을 알 수 있음은 물론 자신의 캐릭터 컨셉 디자인 그림 파일까지 되찾을 수 있겠지만, 그렇다면 시간이 너무 걸린다!


오공 씨는 해당 그림 파일을 당장 32시간 뒤 상사에게 제출하기로 했다. 그래서 오공 씨는 자기 나름대로 열심히 랜섬웨어를 수정해보았지만 원하는 결과를 얻지 못했다.


***또한 심지어 정상적으로 작동하던 프로그램이 지금은 켜지지도 않게 되었다!*** 한참을 고민하다 여기 오공 씨는 당신에게 자신의 파일을 복구해달라고 요청해왔다.


오공 씨를 도와 파일을 복구할 수 있는 숫자를 찾자!


랜섬웨어 : 인터넷 사용자의 컴퓨터에 잠입해 내부 문서나 스프레드 시트, 그림파일 등을 암호화해 열지 못하도록 만든 후 돈을 보내주면 해독용 열쇠 프로그램을 전송해 준다며 금품을 요구하는 악성 프로그램(출처 : 네이버 사전)


랜섬웨어가 주어지는데 실행이 안된다.  약간 조사해보면 Linker Version 이나 Code Size 등등 헤더의 필드들이 이상한 값으로 세팅되어있다.

IDA 로 열어보면 .net 프로그램으로 인식하는데 이것도 PE 헤더 조작으로인한 페이크인것 같다.  사실 일반 x86 바이너리이다.  그런데 IDA 로 열어서 정적분석을 해보니 실행할 필요없이 정적분석만해서 풀 수 있을것 같다.


먼저, 메인함수로 추정되는 부분을 찾았다.



루틴을 보아하니 0~999999 사이의 Input 를 입력받은다음 이것으로 4바이트짜리 XOR 키를 만들어서 그대로 암호화하여 생성된것이 secret.jpg 임을 알 수 있다.  만약 secret.jpg 가 정상적인 JPG 파일이 XOR 키로 암호화된 것이라면 JPG 헤더의 알려진 부분들을 통해 복호화하고 XOR 키또한 바로 찾을수 있다.  JFIF 매직은 고정되어있으므로 XOR 암호화된 처음 파일내용과 두번째 일반 JPG 헤더를 XOR 시키면 바로 KEY 가 나타나게 된다.  






BB ^ FF = 44

CE ^ D8 = 16

DA ^ FF = 25

E6 ^ E0 = 06


KEY : 0x44162506


키를 찾았으니 아래의 파이썬 스크립트로 암호화된 파일을 해독해보니 



역시나 원래의 JPG 이미지가 나타났다.



여기까지는 거의 10분정도만에 끝났다. 남은것은 어떠한 Input 으로부터 XOR 키가 생성되는지만 찾으면 되는데, 여기부터 삽질이 시작됬다.

Input 은 아래의 Hash 함수를 통해 XOR 키로 변환되는데, reverse 할수없어보이므로 방법은 모든 Input 에 대해서 XOR 키를 생성해보고 그중 매칭되는 Input 을 찾는 것이다.




브루트포싱 작업을 위해서 헥스레이 디컴파일 코드들을 기반으로 동일한 로직을 가지고 실제 작동시킬수 있는 C 소스를 만들기 시작했다. 

그런데 여기서 프로그래밍 실수를 했는데 디버깅으로 2시간은 날린것 같다 -_-;  원인은 input 의 길이를 잘못 판단한 것이었는데.. 아무튼

복잡하다.  결과적으로 동일한 시뮬레이션을 할수있는 소스코드는 아래와 같다


#include <stdio.h>


int sub_401000(unsigned int* p)

{

  unsigned int v1; // edx@1

  unsigned int v2; // eax@2

  unsigned int v3; // eax@5

  unsigned int v4; // eax@8

  unsigned int v5; // eax@11

  unsigned int v6; // eax@14

  unsigned int v7; // eax@17

  unsigned int v8; // eax@20

  unsigned int result; // eax@23


  v1 = 0;

  do

  {

    v2 = v1 >> 1;

    if ( v1 & 1 )

      v2 ^= 0xEDB88320;

    if ( v2 & 1 )

      v3 = (v2 >> 1) ^ 0xEDB88320;

    else

      v3 = v2 >> 1;

    if ( v3 & 1 )

      v4 = ((unsigned int)v3 >> 1) ^ 0xEDB88320;

    else

      v4 = (unsigned int)v3 >> 1;

    if ( v4 & 1 )

      v5 = ((unsigned int)v4 >> 1) ^ 0xEDB88320;

    else

      v5 = (unsigned int)v4 >> 1;

    if ( v5 & 1 )

      v6 = ((unsigned int)v5 >> 1) ^ 0xEDB88320;

    else

      v6 = (unsigned int)v5 >> 1;

    if ( v6 & 1 )

      v7 = ((unsigned int)v6 >> 1) ^ 0xEDB88320;

    else

      v7 = (unsigned int)v6 >> 1;

    if ( v7 & 1 )

      v8 = ((unsigned int)v7 >> 1) ^ 0xEDB88320;

    else

      v8 = (unsigned int)v7 >> 1;

    if ( v8 & 1 )

      result = ((unsigned int)v8 >> 1) ^ 0xEDB88320;

    else

      result = (unsigned int)v8 >> 1;

    *(p + v1) = (unsigned int)result;

v1++;

  }

  while ( v1 < 0x100 );


  return result;

}


#define KEY 0x06251644

#define KEY2 0x44162506

#include <string.h>


int main(int argc, char* argv[]){


  unsigned char *v0; // edi@1

  char v1; // al@2

  int v2; // edi@3

  unsigned char *v3; // ebx@3

  unsigned int v4; // esi@3

  signed int v5; // edi@5

  int i; // esi@5

  int v7; // eax@7

  signed int v8; // esi@7

  int v10; // [sp+Ch] [bp-418h]@1

  unsigned int j; // [sp+10h] [bp-414h]@5

  unsigned int v12[256]; // [sp+14h] [bp-410h]@3

  unsigned char v13[10]; // [sp+414h] [bp-10h]@1

 /* 

  printf("Input Key (0~999999): ");

  scanf("%d", &v10);

 */

  

  unsigned int num=0;

  sub_401000(v12);

  

while(1)

  sprintf((char*)v13, "%04d", num);

//  printf("%s\n", v13);

 

  v3 = v13;

  v4 = 0xFFFFFFFF;

  

  int index=0;

  int len = strlen((const char*)v3) -1;

  for (v2=0; v2<len; v2++)

  {

index = ((unsigned char)v4) ^ (*v3);

if(index>255 || index<0){

printf("asdf");

getchar();

}

v4 = (v12[ index ]) ^ (unsigned int)(v4 >> 8);

    v3 = v3 + 1;

  }


  j = ~v4;

  

  if(j==KEY){

 printf("found! : %08x - %d\n", j, num);

  }


  num++;

 

}



sprintf 를 했을때 마지막에 개행문자가 자동으로 붙는것을 망각하는 바람에 0~999999 까지를 input 으로 줬을때 답이 나오지 않았다.  왜 안나오는지 몰라서 이렇게 저렇게 해보다가 자릿수를 늘려서 찾은다음 개행문자 때문인것을 개닳았다 -_-; 아무튼 flag 는 998998 이었다.







'Games > CTF' 카테고리의 다른 글

DEFCON 2013 penser writeup  (0) 2013.06.18
HDCON 2013 level5  (8) 2013.06.11
HDCON 2013 level3  (0) 2013.06.11
HDCON 2013 level1  (0) 2013.06.11
SECUINSIDE 2013 reader  (0) 2013.05.28