[Write-up] Chal6 {Flareon4}

m4n0w4r
tradahacking
Published in
8 min readNov 15, 2017

Write-up for Chal6 of Flareon4. This may not be a good solution, but that’s the method how I found the final flag.

1. Collect information

- Target is a dll file: payload.dll

- Check the basic information:

o File format: PE+(64)

o Resource section of the file doesn’t contain any special information.

o API functions are imported primarily from kernel32.dll and user32.dll.

o Information related to Export function:

Ordinal: 1, Function Name: EntryPoint, RVA: 0x00005C00

o About the string, there are some important strings as following:

“Insert clever error message here!”

“rundll32 payload.dll, EntryPoint EntryPoint” ← This string suggests how to call the function that this dll has exported above.

2. Try to run payload.dll

Try running payload.dll with the above suggestion:

I received the message: “Missing entry: Entrypoint”. So, I think the exported Entrypoint function was altered when running payload.dll.

To check whether the exported function is changed, use x64dbg to debug:

- Load C:\Windows\System32\rundll32.exe into x64dbg.

- Modify the input parameters at Debug > Change Command Line. Edit similarly as following: “”C:\Windows\System32\rundll32.exe” C:\Users\manowar\Desktop\FlareOn4\Chal6\payload.dll, EntryPoint EntryPoint”

- Reconfigure the Options > Preferences, Settings > Envents, select DLL Load & DLL Entry

Then press F9 to run and watch carefully when payload.dll is loaded, stop at DLLMain and execute completely:

Don’t close the above message, using the OllyDumpEx plugin for dumping the entire payload.dll, and then saving as the new name payload_dump_64.dll. Check the dumped file with CFF Explorer, Export function information is changed as following:

Note: Ordinal is still 1, thus can concluding the Entrypoint function has been renamed to basophileslapsscrapping.

Based on above information, try to execute again with the following command: rundll32.exe payload.dll, basophileslapsscrapping basophileslapsscrapping. As a result, I received a message box about 24th character of the flag: (0x6f -> ASCII: ‘o’):

In addition, during the test, try to run the payload.dll by ordinal: rundll32.exe payload.dll, #1. Get the error message box:

3. Analyze and debug payload.dll

Load payload.dll into IDA, first go to exported EntryPoint function at 0x0000000180005C00. Here, I see the code that only shows the usage instructions:

Following the “Insert clever error message here!” string, go to listing at sub_180005A50. Along with the process of analyzing code in IDA, I also use x64dbg to load the payload.dll with parameters passed is (“C:\Windows\System32\rundll32.exe” C:\Users\manowar\Desktop\FlareOn4\Chal6\payload.dll, basophileslapsscrapping basophileslapsscrapping), set a breakpoint at the instruction:

0000000180005A50 mov dword ptr ss:[rsp+0x20], r9d

After deep dive analysis and debug code, get the following information:

int __fastcall sub_180005A50(__int64 a1, __int64 a2, __int64 a3)

{

_DWORD *export_dir; // rax@1

__int64 img_export_dir; // ST48_8@1

unsigned int export_name_VA; // ST38_4@1

char *lpexport_name; // rax@1

__int64 k; // rcx@1

unsigned __int8 chr; // dl@2

int flag; // eax@4

int result; // eax@9

int index_val; // [sp+20h] [bp-168h]@1

signed __int64 len_key; // [sp+28h] [bp-160h]@7

LPVOID lpAddress; // [sp+30h] [bp-158h]@7

__int64 export_func_name; // [sp+40h] [bp-148h]@1

signed __int64 size; // [sp+50h] [bp-138h]@1

DWORD flOldProtect; // [sp+58h] [bp-130h]@7

_DWORD *export_dir_copy; // [sp+60h] [bp-128h]@1

__int64 v18; // [sp+68h] [bp-120h]@7

Rc4Context *context; // [sp+70h] [bp-118h]@9

__int64 v20; // [sp+190h] [bp+8h]@1

__int64 v21; // [sp+198h] [bp+10h]@1

__int64 lpKey; // [sp+1A0h] [bp+18h]@1

lpKey = a3;

v21 = a2;

v20 = a1;

export_dir = (_DWORD *)Get_ExportDirectory(); // Get Export Directory’s addr

export_dir_copy = export_dir;

img_export_dir = *export_dir + Dos_Header; // Get Export Directory Table data (Export_Dir’s RVA + DOS Header)

export_name_VA = *(_DWORD *)(Dos_Header + *(_DWORD *)(img_export_dir + 0x20));// Get RVA that points to export function name

export_func_name = export_name_VA + Dos_Header;// function name

index_val = *(_DWORD *)(img_export_dir + 4) & 0xFF;// index_val = TimeDateStamp & 0xFF

size = (_BYTE *)*(&off_1800198E0 + (unsigned int)(index_val + 1))

- (_BYTE *)*(&off_1800198E0 + (unsigned int)index_val);// off_1800198E0 in .data section

lpexport_name = (char *)(export_name_VA + Dos_Header);

k = lpKey — (_QWORD)lpexport_name;

// Cause command is rundll32 payload.dll, EntryPoint EntryPoint

// This loop checks if the two strings are equal, Export function equals Key (eg. EntryPoint = EntryPoint)

while ( 1 )

{

chr = *lpexport_name;

if ( *lpexport_name != lpexport_name[k] )

{

break;

}

++lpexport_name;

if ( !chr )

{

flag = 0;

goto LABEL_6;

}

}

flag = -(chr < (unsigned __int8)lpexport_name[k]) | 1;

LABEL_6:

if ( flag )

{

MessageBoxA(0i64, “Insert clever error message here!”, “Error”, 0);

result = 0;

}

else

{

lpAddress = *(&off_1800198E0 + (unsigned int)index_val);

VirtualProtect(*(&off_1800198E0 + (unsigned int)index_val), 0x1000ui64, PAGE_EXECUTE_READWRITE, &flOldProtect);// Changes the protection on a region in .text section to ERW; size: 0x1000

v18 = export_func_name;

len_key = 0xFFFFFFFFFFFFFFFFi64;

do

{

++len_key;

}

while ( *(_BYTE *)(v18 + len_key) );

// Initialize an RC4 context using the supplied key

// @param[in] context Pointer to the RC4 context to initialize

// @param[in] key Pointer to the key

// @param[in] length Length of the key

// @return Error code

rc4Init((Rc4Context *)&context, export_func_name, len_key);

// Encrypt/decrypt data with the RC4 algorithm

// @param[in] context Pointer to the RC4 context

// @param[in] input Pointer to the data to encrypt/decrypt

// @param[in] output Pointer to the resulting data

// @param[in] length Length of the input data

rc4Cipher((Rc4Context *)&context, (__int64)lpAddress, (__int64)lpAddress, size);

result = ((int (__fastcall *)(__int64, __int64, __int64, _QWORD))lpAddress)(v20, v21, lpKey, (unsigned int)size);// Call to decrypted payload

}

return result;

}

In summary, sub_180005A50 does the following tasks:

- B1: Get the name of the function exported by payload.dll.

- B2: Calculate an index value based on the TimeDateStamp (this TimeDateStamp value will vary and for each exported function name). Index = TimeDateStamp & 0xFF

- B3: Calculate a size value, this value will be used as the size for the data to be decoded by RC4 algorithm.

- B4: Perform a loop to verify that the name of the exported function is the same as the key to be passed. Because, according to the original instruction, payload.dll must be run with the following syntax (rundll32 payload.dll, EntryPoint EntryPoint), so if not the same, it will show the error message: “Insert clever error message here!”

- B5: Based on the index value obtained in B2, it will be added to off_1800198E0 to retrieve the address location in the .text section as the location to decrypt the data. Through the VirtualProtect API, the access protection of this memory area is changed to PAGE_EXECUTE_READWRITE with a size of 0x1000.

- B6: RC4 context is initialized by using the key provided (key coincides with the name of the exported function).

- B7: Use the initialized context to decode the data region that is obtained in B5 with the calculated size in B3.

- B8: Finally, jump to the decrypted code and execute payload to display the message about the character of final flag in hexadecimal code.

However, I recognized sub_180005A50 that analyzed above is a function handler after the original EntryPoint function was replaced by another function name. Thus, the code that performs the replacement of a new function name has already taken before. How to find this listing?

Deep dive into the code, due to involve taking information about the export function, sub_180005A50 analyzed earlier has other sub_180004760 function (which has been renamed to Get_ExportDirectory):

Placing yourself in the position of coder, they will often write a generic function to perform a certain task. Therefore, the Get_ExportDirectory() function will be called somewhere earlier. By using IDA’s xrefs feature, I found the call to this function at sub_180005D30.

Set a breakpoint at:

0000000180005D30 mov qword ptr ss:[rsp+0x8], rcx

After deep dive analysis and debug code at sub_180005D30, get the following information:

__int64 __fastcall sub_180005D30(__int64 a1)

{

__int64 addr_180005D4D; // rax@1

HANDLE hProcess; // rax@5

__int64 exp_directory; // ST40_8@5

unsigned int index; // ST38_4@5

_WORD *lpAddress; // [sp+30h] [bp-48h]@1

DWORD flOldProtect; // [sp+58h] [bp-20h]@5

__int64 v8; // [sp+80h] [bp+8h]@1

v8 = a1;

LODWORD(addr_180005D4D) = sub_180005E70(); // get addr 0x180005D4D

// Retrieve ImageBase & PE headear address of payload.dll when mapping to memory

for ( lpAddress = (_WORD *)(addr_180005D4D & 0xFFFFFFFFFFFFF000ui64);

!(unsigned int)GetDOSHeader(lpAddress) || !(unsigned int)GetPEHeader((__int64)lpAddress);

lpAddress += 0xFFFFF800 )

{

;

}

hProcess = GetCurrentProcess();

// lpAddress -> ImageBase (0x180000000) of payload.dll

// Change protection to Execute_Read_Write mode

VirtualProtectEx(hProcess, lpAddress, 0x1000ui64, PAGE_EXECUTE_READWRITE, &flOldProtect);

exp_directory = Get_ExportDirectory();

index = GetIndexFromTime();

DecryptExportFunction(index); // Decrypt data base on index value, set new TimeDateStamp and new export function

*(_DWORD *)exp_directory = (index << 9) + (unsigned __int64)byte_180001000 — (_DWORD)lpAddress;// set new RVA of IMAGE_EXPORT_DIRECTORY

*(_DWORD *)(exp_directory + 4) = 0x200; // set new size of IMAGE_EXPORT_DIRECTORY

return v8;

}

In summary sub_180005D30 does the following tasks:

- B1: Perform a loop to obtain information related to ImageBase and PE header of payload.dll when mapped into memory.

- B2: Call VirtualProtectEx to change the access protection on the memory area at the ImageBase to PAGE_EXECUTE_READWRITE.

- B3: Call Get_ExportDirectory() to get information of Export Directory.

- B4: Calculate and index value based on SystemTime, index = (SystemTime.wYear + SystemTime.wMonth) % 26. Thereby, I can conclude that the index value will be in the range of 0 -> 25.

- B5: Based on the calculated index earlier, call DecryptExportFunction(index) function to decode data, and then reset the TimeDateStamp value and the new name of export function.

- B6: Finally, adjust the RVA value and new size of IMAGE_EXPORT_DIRECTORY.

After obtaining the new information about TimeDateStamp and the new export function name, they will be used at sub_180005D30 to decode corresponding to the index position in the flag.

So, if I manually change each index value that returned by GetIndexFromTime() function, in the range from 0–25, I finally get the following export functions :

index[0] = filingmeteorsgeminately

index[1] = leggykickedflutters

index[2] = incalculabilitycombustionsolvency

index[3] = crappingrewardsanctity

index[4] = evolvablepollutantgavial

index[5] = ammoniatesignifiesshampoo

index[6] = majesticallyunmarredcoagulate

index[7] = roommatedecapitateavoider

index[8] = fiendishlylicentiouslycolouristic

index[9] = sororityfoxyboatbill

index[10] = dissimilitudeaggregativewracks

index[11] = allophoneobservesbashfulness

index[12] = incuriousfatherlinessmisanthropically

index[13] = screensassonantprofessionalisms

index[14] = religionistmightplaythings

index[15] = airglowexactlyviscount

index[16] = thonggeotropicermines

index[17] = gladdingcocottekilotons

index[18] = diagrammaticallyhotfootsid

index[19] = corkerlettermenheraldically

index[20] = ulnacontemptuouscaps

index[21] = impureinternationalisedlaureates

index[22] = anarchisticbuttonedexhibitionistic

index[23] = tantalitemimicryslatted

index[24] = basophileslapsscrapping

index[25] = orphanedirreproducibleconfidences

According to FLARE-ON’s flag structure, the final flag will has the format: [chars]@flare-on.com. Based on the above index information, I conclude that the flag has 26 characters (the 24th character is known as ‘o’). So try each export function until get the message that the character corresponding to index = 13 has a hex code is 0x40 (ASCII code is ‘@’).

Finally got the flag to submit is: wuuut-exp0rts@flare-on.com

--

--