본문 바로가기
[CTF]

[DREAMHACK] darimchal_001

by 준제 2023. 9. 9.

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

 

darimchal_001

이야기 드림이는 평화로운 오후, 드림핵으로 해킹공부를 하고 있었습니다. 그런데 갑자기! [ 드림이의 | 컴퓨터가 | 잠겨버렸습니다 ] 그렇습니다... 드림이의 친구 다리미... 결국 늘 드림이에게

dreamhack.io

 

문제에서 주어진 것들을 살펴보자. 받은 파일의 압축을 해제하면 C언어로 구성된 코드와 리눅스 환경에서 코드를 실행할 수 있는 파일 두가지로 구성되어있다. 본문에서는 XOR연산으로 암호화 했다는 힌트를 제공했다.

원래대로면 리눅스에서 파일을 실행하여 문제를 해결해야 하는데, C코드를 분석해서 푸는 문제이기 때문에 굳이 리눅스 환경을 구현하지 않아도 된다.

 


 

#include와 #define부터 시작해 코드를 본격적으로 분석하자.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define JOKER "\x40\x53\x06\x03\x43\x52\x54\x3b"
#define KEY   "023661dd4\0"
#define TRUE  1
#define FALSE 0
#define OK    0
#define ERRO -1

 

눈여겨 볼 것은 JOKER와 KEY의 정의다. 두 개를 다른 형태로 표현하긴 했으나 각각 8자리, 9자리 16진수임을 알 수 있다.

 


 

main 함수를 살펴보자.

 

int main (int argc, char *argv[]) {
  if (argc != 2) {
    __print_sw_title(argv[0]);
    return ERRO;
  }

  if ( __is_valid_pwd(argv[1]) ) {
    __create_tag(argv[0]);
    printf("\n +-+ 무, 무슨... 말도 안돼!! 어떻게 복호화 키를...?? +-+ \n");
  } else {
    printf("\n 너의 파일들은 이제 요단강을 건너다가 저승사자와 하이파이브를 하게되었다! 으하하하하!\n"); // ㅋㅋㅋㅋㅋㅋ
  }

  return OK;
}

 

첫번째 if문은 코드가 리눅스 환경에서 제대로 실행되었는지 검사한다. 리눅스 환경이 아니라면  __print_sw_title(argv[0])를 실행하고 코드를 강제종료한다.

두번째 if문은 __is_valid_pwd(argv[1])가 들어있다. 아래 출력문을 보면 이 함수가 참일 때 복호화에 성공한다는 것을 알 수 있다. __create_tag(argv[0]) __is_valid_pwd(argv[1])가 참일 때만 실행된다.

 


 

main에서 사용된 세 함수를 살펴보자.

 

void __print_sw_title (char *sw_name) {
  printf(" ----------- [%s] ----------- \n", sw_name);
  printf(" ::. 복호화 방법: %s <복호화키>\n\n", sw_name);
}

void __create_tag (char *id) {
  FILE *fd;
  char *tag_name = (char *)malloc(24 * sizeof(char));
  memset(tag_name, '\0', 24);
  snprintf(tag_name,24, "./%s.success", id);
  fd = fopen(tag_name, "w");
  if (fd != NULL) {
    fprintf(fd, "복호화가 완료되었습니다.\n");
    fclose(fd);
  } else {
    printf("[ }{4k3r m3ss493 ] Hey sussy baka~ 7h3r3 w4s 4n 3rr0r 0p3nin9 7h3 file..\n");
  }
}

 

__print_sw_title(argv[0]), __create_tag(argv[0])는 암호화와 관련이 없으니 해석을 생략한다. 

 

int __is_valid_pwd (char *pwd) {
  if (! strncmp(JOKER, __obfuscation(pwd, KEY), sizeof(JOKER)) ) {
    return TRUE;
  }

  return FALSE;
}

char *__obfuscation (char *pwd, char *key) {
  int i;
  for (i = 0; i < strlen(pwd); i++) {
    if(key[i] == '\0') break;
    pwd[i] = pwd[i] ^ key[i];
  }

  return pwd;
}

 

__is_valid_pwd(argv[1])는 JOKER와 __obfuscation(pwd, KEY)가 가진 각각의 문자를 JOKER의 크기(8자리)만큼 비교하는 함수다. __obfuscation(pwd, KEY)는 이 코드의 핵심으로, pwd와 key를 XOR 연산 한 후 반환한다.

 


 

코드의 분석이 끝났다. 필요한 부분만 요약한다면,  pwd ^ KEY가 JOKER와 같을 때 참을 출력하는 코드이다. 따라서 우리가 구하고자 하는 pwd는 JOKER ^ KEY 를 하면 얻을 수 있다. 여기부터는 주어진 코드를 살짝 변환하여 리눅스 환경에서 실행해도 되고, 새 파일에 XOR 코드를 구현해도 된다.

 

#include <stdio.h>
#include <string.h>

#define JOKER "\x40\x53\x06\x03\x43\x52\x54\x3b"
#define KEY   "023661dd4\0"

int main() {
    int i;
    for (i = 0; i < strlen(JOKER); i++) {
      if(KEY[i] == '\0') break;
      printf("%c", JOKER[i] ^ KEY[i]);
    }
}

 

출력 하면 pa55uc0_ 를 얻을 수 있고, 언더바(_)를 제거한 뒤 입력하면 정답이다.

'[CTF]' 카테고리의 다른 글

[CTF] png 파일 속에 jpg 파일 숨기기 (steganography)  (0) 2023.10.01
[CTF] 파일 시그니처  (0) 2023.09.30
[DREAMHACK] rev-basic 4~6  (0) 2023.09.19
[DREAMHACK] rev-basic 1~3  (0) 2023.09.11
[DREAMHACK] SingleByteXor  (0) 2023.08.28