chon

[Dreamhack] Happy New Year! 본문

Reversing/Dreamhack Write up

[Dreamhack] Happy New Year!

chon29 2026. 1. 14. 01:06

[ 문제 링크 | https://dreamhack.io/wargame/challenges/2650 ]

 

이 문제는 진짜 조심해야 해요. 근데 일단 전 다운 받아서 풀었어요.

조심하라고 경고했어요.


[ 문제 설명 ]

드림핵 워게임 reversing LEVEL1

문제에 대한 설명은 딱히 없어요! 새해 복 많이 받으세요.

 

[ 문제 풀이 ]

프로그램을 실행하면 "Input : "이라는 메시지와 함께 입력을 받고  입력값을 검증하여 correct나 wrong을 출력합니다.

 

- IDA 디컴파일

IDA로 코드를 분석해보면 main 함수에서 다음과 같은 핵심 로직을 발견할 수 있습니다.

printf("Input : ");
  __isoc99_scanf("%59s", s);
  if ( strlen(s) == 59 )
  {
    strcpy(dest, s);
    for ( i = 0; i <= 58; ++i )
      dest[i] ^= *((_BYTE *)v5 + i);
    if ( !strcmp(dest, "Please_input_the_correct_new_year_greetings_at_this_problem") )
      printf("Correct! Flag is DH{%s}\n", s);
    else
      puts("Wrong!");
  }
  else
  {
    puts("Wrong!");
  }
  return 0;
}

코드를 해석하면

   1. 사용자에게 59글자의 (s) 문자열을 입력받습니다.
   2. 이 입력 문자열(s)을 어딘가에 있는 59바이트짜리 비밀키(Secret Key)와 한 글자씩 XOR 연산을 합니다.
   3. XOR 연산이 끝난 결과가 특정 문자열("Please_input_the_correct...")과 일치하는지 확인합니다.
   4. 일치하면 우리가 입력한 59글자가 바로 플래그라고 알려주며 "Correct!"를 출력합니다.

 

dest[i] ^= *((_BYTE *)v5 + i);
C 언어에서 ^= 연산자는 비트와이즈 XOR 할당 연산자입니다.

이는 dest[i] = dest[i] ^ *((_BYTE *)v5 + i); 와  동일한 의미로 이 연산자 자체가 비트 XOR 연산을 수행한다는 것을 명확하게 알려줍니다.

 

v5 배열은 40바이트인데,  for문은 59번이나 돌면서 v6까지 보는 이유는 *((_BYTE *)v5 + i) 코드에 있습니다.

C언어의 '형 변환(Type Casting)' 문법으로 v5의 메모리 주소에서 i칸 만큼 앞으로 가서, 거기에 있는 딱 한 칸의 값만 가져오라는 뜻입니다.

 

역연산 코드

secret_key = bytes([
    0x18, 0x0D, 0x15, 0x11, 0xA1, 0xA0, 0x13, 0xC3,
    0x19, 0x2F, 0x47, 0x44, 0x6D, 0x42, 0x37, 0x2C,
    0x00, 0x0F, 0x00, 0x04, 0x17, 0x3A, 0x1A, 0x1B,
    0x2A, 0x31, 0x04, 0x19, 0x3B, 0x26, 0x01, 0x13,
    0x17, 0x3E, 0x0A, 0x1A, 0x04, 0x06, 0x1F, 0x36,
    0x02, 0x02, 0x07, 0x2C, 0x3E, 0x1C, 0x3E, 0x04,
    0x18, 0x10, 0x2C, 0x2B, 0x1F, 0x15, 0x0A, 0x16,
    0x04, 0x00, 0x1F
])

target = b"Please_input_the_correct_new_year_greetings_at_this_problem"

flag = bytes(t ^ k for t, k in zip(target, secret_key))

print(f"DH{{{flag.decode()}}}")

어셈블리 코드에서 알아낸 정확한 값들을 사용해 59바이트짜리 완전한 비밀키를 만들고, 위에서 설명한 XOR연산을 적용하면 우리가 찾던 정답이 나옵니다.

 

리틀 엔디언이란, 숫자의 가장 낮은 자리(가장 오른쪽) 바이트부터 메모리에 먼저 저장하는, 즉 '거꾸로 저장'하는 방식입니다.

이 원리를 이 문제의 8바이트(QWORD) 값인 0xC313A0A11150D18에 적용했습니다.

   1. 먼저 8바이트 숫자를 바이트 단위로 나눕니다.
      > C3 13 A0 A1 11 15 0D 18

   2. 리틀 엔디언 규칙에 따라, 오른쪽 바이트부터 순서대로 메모리에 나열합니다.
      > 18 0D 15 11 A1 A0 13 C3

이것이 바로 아래 역연산 코드에 있는 secret_key의 첫 8바이트가 0x18, 0x0D, 0x15, ... 로 시작하는 이유입니다.
나머지 숫자들도 모두 이와 같은 방식으로 변환하여 59바이트 길이의 완전한 secret_key를 조합한 것입니다.

 

따라서 XOR 연산(플래그 = 목표 문자열 ^ 비밀키)으로 플래그를 얻을 수 있습니다.

'Reversing > Dreamhack Write up' 카테고리의 다른 글

[Dreamhack] Recover  (0) 2026.01.16
[Dreamhack] Simple Crack Me Write up  (0) 2025.12.14
[Dreamhack] randzzz Write up  (0) 2025.11.20
[Dreamhack] rev-basic-4 Write up  (1) 2025.11.18
[Dreamhack] rev-basic-3 Write up  (0) 2025.11.02