PicoCTF - gogo

PicoCTF - gogo

Source code

:::spoiler IDA Main Function

// main.main
void __cdecl main_main()
{
  _slice_interface_ typ[2]; // [esp+0h] [ebp-58h] BYREF
  string *second_flag; // [esp+20h] [ebp-38h]
  string *flag; // [esp+24h] [ebp-34h]
  _slice_interface_ v3; // [esp+28h] [ebp-30h] BYREF
  string *v4; // [esp+34h] [ebp-24h]
  _DWORD v5[2]; // [esp+38h] [ebp-20h] BYREF
  _DWORD v6[2]; // [esp+40h] [ebp-18h] BYREF
  _slice_interface_ v7; // [esp+48h] [ebp-10h] BYREF
  string *v8; // [esp+54h] [ebp-4h]

  flag = runtime_newobject(&RTYPE_string_0);
  typ[0].array = "Enter Password: ";
  typ[0].len = 16;
  memset(&typ[0].cap, 0, sizeof(_slice_interface_));
  fmt_Printf(*&typ[0].array, *&typ[0].cap);
  v6[0] = &RTYPE__ptr_string;
  v6[1] = flag;
  typ[0].array = "%s\n";
  typ[0].len = 3;
  typ[0].cap = v6;
  *&typ[1].array = 0x100000001LL;
  fmt_Scanf(*&typ[0].array, *&typ[0].cap);
  if ( main_checkPassword(*flag) )
  {
    v5[0] = &RTYPE_string_0;
    v5[1] = &main_statictmp_0;
    typ[0].array = v5;
    *&typ[0].len = 0x100000001LL;
    fmt_Println(typ[0]);
    v3.cap = &RTYPE_string_0;
    v4 = &main_statictmp_1;
    typ[0].array = &v3.cap;
    *&typ[0].len = 0x100000001LL;
    fmt_Println(typ[0]);
    v3.array = &RTYPE_string_0;
    v3.len = &main_statictmp_2;
    typ[0].array = &v3;
    *&typ[0].len = 0x100000001LL;
    fmt_Println(typ[0]);
    second_flag = runtime_newobject(&RTYPE_string_0);
    v7.cap = &RTYPE__ptr_string;
    v8 = second_flag;
    typ[0].array = "%s\n";
    typ[0].len = 3;
    typ[0].cap = &v7.cap;
    *&typ[1].array = 0x100000001LL;
    fmt_Scanf(*&typ[0].array, *&typ[0].cap);
    main_ambush(*second_flag);
    runtime_deferproc(0, &stru_81046A0);
  }
  else
  {
    v7.array = &RTYPE_string_0;
    v7.len = &main_statictmp_3;
    typ[0].array = &v7;
    *&typ[0].len = 0x100000001LL;
    fmt_Println(typ[0]);
  }
  runtime_deferreturn(typ[0].array);
}

:::

:::spoiler IDA First Stage Checker

// main.checkPassword
bool __golang main_checkPassword(string flag)
{
  __int32 idx; // eax
  int check_counter; // ebx
  uint8 key[32]; // [esp+4h] [ebp-40h] BYREF
  char enc_flag[32]; // [esp+24h] [ebp-20h]

  if ( flag.len < 32 )
    os_Exit(0);
  (loc_8090B18)();
  qmemcpy(key, "861836f13e3d627dfa375bdb8389214e", sizeof(key));
  (loc_8090FE0)();
  idx = 0;
  check_counter = 0;
  while ( idx < 32 )
  {
    if ( idx >= flag.len || idx >= 0x20 )
      runtime_panicindex();
    if ( (key[idx] ^ flag.str[idx]) == enc_flag[idx] )
      ++check_counter;
    ++idx;
  }
  return check_counter == 32;
}

:::

:::spoiler IDA Second Stage Checker

// main.ambush
void __golang main_ambush(string second_flag)
{
  int j; // eax
  _slice_uint8 v2; // [esp+0h] [ebp-94h]
  _slice_uint8 s; // [esp+4h] [ebp-90h]
  _slice_uint8 dataa; // [esp+Ch] [ebp-88h]
  string data; // [esp+Ch] [ebp-88h]
  string data_4; // [esp+10h] [ebp-84h]
  uint8 v7; // [esp+1Fh] [ebp-75h]
  unsigned __int32 i; // [esp+20h] [ebp-74h]
  uint8 hashed[16]; // [esp+24h] [ebp-70h] BYREF
  uint8 key[32]; // [esp+34h] [ebp-60h] BYREF
  uint8 buf[32]; // [esp+54h] [ebp-40h] BYREF
  uint8 v12[32]; // [esp+74h] [ebp-20h] BYREF

  dataa = runtime_stringtoslicebyte(buf, second_flag);
  crypto_md5_Sum(dataa);
  (loc_8091008)();
  (loc_8090B18)();
  qmemcpy(key, "861836f13e3d627dfa375bdb8389214e", sizeof(key));
  for ( j = 0; j < 16; j = i + 1 )
  {
    i = j;
    v2.array = hashed;
    *&v2.len = 0x1000000010LL;
    data = encoding_hex_EncodeToString(v2);
    if ( i >= data.len
      || (v7 = data.str[i],
          s.array = key,
          *&s.len = 0x2000000020LL,
          data_4 = runtime_slicebytetostring(v12, s),
          i >= data_4.len) )
    {
      runtime_panicindex();
    }
    if ( v7 != data_4.str[i] )
      os_Exit(0);
  }
}

:::

Recon

終於有一點像樣的題目出現了,這一題有兩個關卡需要克服

1
2
$ file enter_password
enter_password: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=3-hVI6nMz0HbfIUMSEzq/TkiA8oRk8FHsCuRXIle2/C1my_KvOIt2KUk44LyQs/-XrwOx7UDhcGGdtF5xpG, with debug_info, not stripped

用IDA和gdb跟一下整體的流程

  1. 首先他先把我們輸入的flag,丟到main_checkPassword function檢查,而跟了一下gdb發現他是先跟861836f13e3d627dfa375bdb8389214e的每一個數值進行xor然後跟enc_flag的字元做比較,而enc_flag是run time的時候需要從memory撈的資料,這就需要慢慢跟然後慢慢看,大概就像下面撈的那樣,反著作就可以得到第一階段的flag
  2. 過了第一階段後他還會叫你要再輸入一次另外一個flag,然後會丟到main_ambush function做檢查,他會先把我們輸入的second flag進行md5的hash,然後和861836f13e3d627dfa375bdb8389214e進行比對,所以我們要做的事情是推測甚麼樣的字串,他的md5 hash是861836f13e3d627dfa375bdb8389214e,這個可以用online tool做到這件事情

Exploit

  1. Script For 1st Stage
    1
    2
    3
    4
    5
    6
    7
    8
     enc_flag = [74, 83, 71, 93, 65, 69, 3, 84, 93, 2, 90, 10, 83, 87, 69, 13, 5, 0, 93, 85, 84, 16, 1, 14, 65, 85, 87, 75, 69, 80, 70, 1]
     key = [0x38, 0x36, 0x31, 0x38, 0x33, 0x36, 0x66, 0x31, 0x33, 0x65, 0x33, 0x64, 0x36, 0x32, 0x37, 0x64, 0x66, 0x61, 0x33, 0x37, 0x35, 0x62, 0x64, 0x62, 0x38, 0x33, 0x38, 0x39, 0x32, 0x31, 0x34, 0x65]
    
     FLAG = []
     for a, b in zip(enc_flag, key):
         FLAG.append(bytes.fromhex(hex(a ^ b)[2:]).decode('utf-8'))
    
     print("".join(FLAG))
    
  2. Use online tool to unhash

  3. Conclusion
    1
    2
    3
    4
    5
    6
    7
     $ nc mercury.picoctf.net 4052
     Enter Password: reverseengineericanbarelyforward
     =========================================
     This challenge is interrupted by psociety
     What is the unhashed key?
     goldfish
     Flag is:  picoCTF{p1kap1ka_p1c09a4dd7f3}