Compy's Blog
841 words
4 minutes
[DreamHack] dungeon-in-1983
2024-10-05
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int i; // [rsp+14h] [rbp-1BCh]
  char *lineptr; // [rsp+18h] [rbp-1B8h] BYREF
  size_t ptr; // [rsp+20h] [rbp-1B0h] BYREF
  FILE *stream; // [rsp+28h] [rbp-1A8h]
  __int64 v8[2]; // [rsp+30h] [rbp-1A0h] BYREF
  int v9; // [rsp+40h] [rbp-190h]
  __int64 v10; // [rsp+44h] [rbp-18Ch]
  __int64 v11; // [rsp+4Ch] [rbp-184h]
  int v12; // [rsp+54h] [rbp-17Ch]
  __int64 v13; // [rsp+58h] [rbp-178h]
  __int64 v14; // [rsp+60h] [rbp-170h]
  int v15; // [rsp+68h] [rbp-168h]
  __int64 v16; // [rsp+6Ch] [rbp-164h]
  __int64 v17; // [rsp+74h] [rbp-15Ch]
  int v18; // [rsp+7Ch] [rbp-154h]
  __int64 v19; // [rsp+80h] [rbp-150h]
  __int64 v20; // [rsp+88h] [rbp-148h]
  int v21; // [rsp+90h] [rbp-140h]
  __int64 v22; // [rsp+94h] [rbp-13Ch]
  __int64 v23; // [rsp+9Ch] [rbp-134h]
  int v24; // [rsp+A4h] [rbp-12Ch]
  __int64 v25; // [rsp+A8h] [rbp-128h]
  __int64 v26; // [rsp+B0h] [rbp-120h]
  int v27; // [rsp+B8h] [rbp-118h]
  __int64 v28; // [rsp+BCh] [rbp-114h]
  __int64 v29; // [rsp+C4h] [rbp-10Ch]
  int v30; // [rsp+CCh] [rbp-104h]
  __int64 v31; // [rsp+D0h] [rbp-100h]
  __int64 v32; // [rsp+D8h] [rbp-F8h]
  int v33; // [rsp+E0h] [rbp-F0h]
  __int64 v34; // [rsp+E4h] [rbp-ECh]
  __int64 v35; // [rsp+ECh] [rbp-E4h]
  int v36; // [rsp+F4h] [rbp-DCh]
  char s[200]; // [rsp+100h] [rbp-D0h] BYREF
  unsigned __int64 v38; // [rsp+1C8h] [rbp-8h]

  v38 = __readfsqword(0x28u);
  v8[0] = 0x6B73696C69736142LL;
  v8[1] = 0LL;
  v9 = 0;
  v10 = 0x6172656D696843LL;
  v11 = 0LL;
  v12 = 0;
  v13 = 0x6E656B61724BLL;
  v14 = 0LL;
  v15 = 0;
  v16 = 0x6E6F67726F47LL;
  v17 = 0LL;
  v18 = 0;
  v19 = 0x6F6769646E6557LL;
  v20 = 0LL;
  v21 = 0;
  v22 = 0x727561746F6E694DLL;
  v23 = 0LL;
  v24 = 0;
  v25 = 0x616874616976654CLL;
  v26 = 110LL;
  v27 = 0;
  v28 = 0x6172647948LL;
  v29 = 0LL;
  v30 = 0;
  v31 = 0x726F6369746E614DLL;
  v32 = 101LL;
  v33 = 0;
  v34 = 6516562LL;
  v35 = 0LL;
  v36 = 0;
  sub_130A(a1);
  stream = fopen("/dev/urandom", "r");
  puts("Welcome to the Dungeon!");
  puts("You have only two buttons: A and B.");
  puts("Each monster requires certain series of key combinations to be defeated, so be careful!");
  for ( i = 0; i <= 9; ++i )
  {
    fread(&ptr, 8uLL, 1uLL, stream);
    printf("[STAGE %2d]: %s\n", (unsigned int)(i + 1), (const char *)v8 + 20 * i);
    sub_138D(ptr);
    printf("Cast your spell!: ");
    fgets(s, 200, stdin);
    if ( s[strlen(s) - 1] == 10 )
      s[strlen(s) - 1] = 0;
    if ( !(unsigned int)sub_1407(s, ptr) )
    {
      puts("You were defeated. Retreat!");
      exit(-1);
    }
    printf("%s defeated. STAGE %2d cleared!\n", (const char *)v8 + 20 * i, (unsigned int)(i + 1));
  }
  fclose(stream);
  printf("It's dangerous to go alone! Take the flag: ");
  lineptr = 0LL;
  ptr = 0LL;
  stream = fopen("./flag", "r");
  getline(&lineptr, &ptr, stream);
  printf("%s", lineptr);
  free(lineptr);
  fclose(stream);
  return 0LL;
}

요건 메인이고, 우리가 볼 로직은 function - sub_1407입니다.





_BOOL8 __fastcall sub_1407(__int64 a1, __int64 a2)
{
  int v2; // eax
  int v4; // [rsp+1Ch] [rbp-14h]
  int v5; // [rsp+20h] [rbp-10h]
  int i; // [rsp+24h] [rbp-Ch]
  __int64 v7; // [rsp+28h] [rbp-8h]

  v7 = 0LL;
  v4 = 0;
  v5 = 0;
  for ( i = 0; *(_BYTE *)(i + a1); ++i )
  {
    v2 = *(char *)(i + a1);
    if ( v2 == 65 )
    {
      v5 = 1;
      ++v7;
      if ( v4 )
      {
        puts("A button stucked! Retreat...");
        exit(-1);
      }
      v4 = 1;
    }
    else
    {
      if ( v2 != 66 )
      {
        puts("Invalid button!");
        exit(-1);
      }
      if ( !v5 )
      {
        puts("Lore says the spell should start with A...");
        exit(-1);
      }
      v7 *= 2LL;
      v4 = 0;
    }
  }
  return v7 == a2;
}
  • A가 나오면 결과에 1을 더함
  • B가 나오면 결과를 2배로 늘림

뭐 요걸 역연산해서 얻어내는 것이다! 뭐 이렇게 하면됩니다.

딱히 어려운 아이디어는 아닌 것 같아 여기까지만 하겠습니다.

조심조심
63 ~ 4847 ~ 4039 ~ 3231 ~ 2423 ~ 1615 ~ 87 ~ 0
HIWORDBYTE5BYTE4BYTE3BYTE2BYTE1(u_int8)
정답코드
from pwn import *


def solution(input_value):
    def parse(input_value: str):
        # [INFO]를 없앨거임
        input_value = input_value[7:]
        input_value = input_value.split(', ')
        values = []
        print(input_value)
        for i in input_value:
            print(i)
            values.append(int(i.split(': ')[1].replace('\'', '')))
        print(values)
        # 16bit, 8bit, 8bit, 8bit, 8bit, 8bit, 8bit

        # 64bit
        result = values[0] << 48
        for i in range(1, len(values)): result += values[i] << ((8 * (i-1)))

        '''
        63    48 47    40 39    32 31    24 23    16 15     8 7      0
        +--------+--------+--------+--------+--------+--------+--------+
        | HIWORD |  BYTE5 |  BYTE4 |  BYTE3 |  BYTE2 |  BYTE1 | (u_int8)|
        +--------+--------+--------+--------+--------+--------+--------+
        
        요걸 반대로 생각해서 너무 오래걸림
         ㅠㅜ
        '''

        return result

    if type(input_value) == bytes:
        input_value = str(input_value)[2:]

    stack = b''

    value = parse(input_value)
    print(value)
    while value > 1:
        if value & 1 == 0:
            value >>= 1
            stack += b'B'
        else:
            value -= 1
            stack += b'A'

    stack += b'A'

    return ''.join([chr(i) for i in reversed(stack)])


#
p = remote("host3.dreamhack.games", 14186)
for i in range(10):
    result = solution(p.recvline_startswith(b"[INFO] "))
    print(result)
    p.sendline(result)
    # p.interactive()

p.interactive()
[DreamHack] dungeon-in-1983
https://compy07.github.io/Blog/posts/security/crypto/dreamhack/level_1/dungeon-in-1983/
Author
뒹굴뒹굴 이정훈 공부방
Published at
2024-10-05