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 |