flag: SSD{4g3nt_h3ker}
analyze mspaint.exe.dmp with Windbg, the dump was created in the Sleep function, called by mspaint.exe+80FC The function at mspaint.exe+80FC is clearly not an mspaint, briefly:
- xor data 0xC2E0F bytes starting from 0x409020 with 0x45
- write this data to
fname = {getenv("temp")}/installer.exe - call system(fname)
- enter in an infinite loop of remove(fname); sleep(1000)
This program writes to a temp folder:
- Idauud.exe -> which is the AutoIt interpret
- acryprtgh.vsl -> an AutoIt script
- wfmlrmkokn.idu -> a blob file
- oon80gy9qs.exe -> which is a patched version of Idauud.exe, with changed:
- coff_characteristics characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE from IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE | IMAGE_FILE_32BIT_MACHINE
- pe_dll_characteristics dllCharacteristics = IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE from IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
- stripped certificateTableEntry
- Executes
Idauud.exe acryprtgh.vsl
Writes a shellcode in $X35cqbeuflb, and executes it with VirtualAlloc + DllCallAddress chain
It can be reversed with the help of a debugger and a ghidra script ssd-ghidra-hash-resolver.py.
You can find a partial recovered source code of the shellcode there
Briefly this shellcode:
- Checks the list of running processes for blacklisted names with some hashes, if something is present sleeps for 31000 milliseconds
processHash1 = 0x2d734193; processHash2 = 0x63daa681; processHash3 = 0x26090612; processHash4 = 0x6f28fae0; isOk = isProcessRunning(0x2d734193); if ((((isOk != 0) || (isOk = isProcessRunning(processHash2), isOk != 0)) || (isOk = isProcessRunning(processHash3), isOk != 0)) || (isOk = isProcessRunning(processHash4), isOk != 0)) { (*Sleep)(31000); }
- Open, read and decrypt the file
wfmlrmkokn.idu, key =5de30f380d8c4207a4cb023b896b0e0b, with functiondecryptBufferlocated at .base+0x128b. The decrypted result is a PE file - In the end it does some wierd checks in the function @.text+0x027a and problably executes the decrypted buffer, since it a PE. I didn't reverse the shellcode anymore at this point.
Didn't reverse in deep, just noticed that in the main function it does something with the resources, Opening this file with PEview, It is easy to spot that a resource is a PE file @file+0x11458 I extracted this PE with this script:
with open('./another_pe.exe', 'rb') as f:
x = f.read()
stage5 = x[0x11458:0x47448+0x10]
print (len(stage5))
print (len(x[0x11458:]))
with open('last.exe', 'wb') as f:
f.write(stage5)The last PE is an obfuscated .net binary.
Opening it in dnSpy, I spotted that a big array is constructed and decrypted in static A49AA8D2-8915-4BE8-ACA2-15CECAABE69C():
A49AA8D2-8915-4BE8-ACA2-15CECAABE69C.<<EMPTY_NAME>> = new byte[]
{
159, 210, 209, 208, 215, 130, 225, 224, 143, 199,
196, 129, 238, 239, 158, 200, 215, 129, 203, 202,
199, 198, 197, 196, 237, 254, 253, 238, 210, 211,
...
for (int i = 0; i < A49AA8D2-8915-4BE8-ACA2-15CECAABE69C.<<EMPTY_NAME>>.Length; i++)
{
A49AA8D2-8915-4BE8-ACA2-15CECAABE69C.<<EMPTY_NAME>>[i] = (byte)((int)A49AA8D2-8915-4BE8-ACA2-15CECAABE69C.<<EMPTY_NAME>>[i] ^ i ^ 170);
}Applying the decryption in python reveals the file last.extracted, which grepping for the flag yields:
[email protected]_p@sssSSD{4g3nt_h3ker} -> so the flag should be SSD{4g3nt_h3ker}