Challenge 2 of Zero2Auto biweekly challenges
Table of Contents
IcedID malware challenge
This is a malware challenge related to the Zero2Automated course (number 2 out of currently 4).
The aim for this challenge was to unpack this IcedID binary, figure out how the configuration was stored, and develop a script to automatically extract the config information. The malware bazaar link also lets us know that the following IOC exists: ilekvoyn[.]com
Unpacking
In this case the file is a DLL file containing a number of exports.
Exports:
- DllRegisterServer
- HdQZgne
- IfkPmdu
- cJPSuqHBMN
- pcufUY
- rHqnYSA
- zlmkoZLQMd
To execute this DLL for dumping via x64dbg it is executed with the help of rundll32.exe. Out of the existing exports, the DllRegisterServer looks the least suspicious, so we will start by executing that function.
"C:\Windows\System32\rundll32.exe" c:\Users\me\Desktop\0581f0bf260a11a5662d58b99a82ec756c9365613833bce8f102ec1235a7d4f7.dll,DllRegisterServer
To dump the extracted file, we set a breakpoint on VirtualAlloc and VirtualProtect.
After returning fom VirtualAlloc, the register rax contains 180000000, this area is later filled with a PE file.
A future analysis could include figuring out, how the file is exactly loaded into memory, as there no visible imports of VirtualAlloc and VirtualProtect, LoadLibraryA and GetProcAddress.
The allocated memory is then dumped and fixed via PE-bear so that the dump can be loaded into a disassembler.
Decrypting the configuration
This new file is not very large, so the number of functions is limited and a function for gathering data and sending data via http requests can be identified. Furthermore, the path from the _start of the file to the decryption function is rather short, basically a thread is started and sleeps for a bit followed by a call to the decryption function. Before these functions are called there is a function that iterates over some memory and XORs part of that area with another part of data.
xor r8d, r8d {0x0}
lea r9, qword ptr [config]
sub rcx, r9
lea rdx, qword ptr [r8+r9]
inc r8
mov al, byte ptr [rdx+0x40]
xor al, byte ptr [rdx]
mov byte ptr [rcx+rdx+0x40], al
cmp r8, 0x20
jb 0x180002435
ret {__return_addr}
This code uses the first 0x20 bytes at the offset config to decrypt the next bytes.
The following screenshot shows the data at the config offset and at the bottom the output of the Python script presented in the next step.
Python script - binja
This is a small python script executed in the binja script editor to extract the c2 domain out of the config, the output is visible at the end of the previous screenshot.
bv.begin_undo_actions()
r = current_selection
start = r[0]
c2 = ""
for i in range(0x20):
key_byte = (bv.read_int(start + i,1))
byte_to_decrypt = bv.read_int(start + i + 0x40, 1)
decode = (key_byte ^ byte_to_decrypt) % 256
if i >= 4:
c2 += chr(decode)
print("C2:", c2)
bv.commit_undo_actions()
C2 domain: ilekvoyn[.]com
It is possible that the config contains a bit more data, this might be interesting for a future look at it, the goal of this short writeup was just to extract the C2 domain.