In this article, we describe how Hancitor compromises systems based on its infection chain observed in January and February 2021. We cover its unpacking routine, information gathering and command and control (C2) functions, and payload execution techniques.
The malware Hancitor
Hancitor (aka Chanitor) is a downloader which is used to gain initial access to a victim’s computer. Its main purpose is to download and execute a second stage malware payload from one of multiple encrypted URLs contained in the malware itself. This downloader was first seen in 2014 commonly deploying Pony and Vawtrak malware. Like many other malware families we saw Hancitor become active again in early 2021 following the festive period. The first Hancitor malicious spam wave of 2021 started on 12 January, where the malware was distributed as email Word document attachments. Since then, almost every workday we have seen Hancitor activity.
Word Dropper used by Hancitor
On Tuesday 12 January, phishing emails with hyperlinks leading to Word documents reached users’ inboxes. The Word documents were droppers that install and execute the Hancitor downloader. When opened, the user sees a social engineering image telling them that they must click the “Enable editing” button to see the document’s contents.
Figure 1 – Word document lure requesting the user to run the VBA macro.
Analyzing the attachment using oledump shows that not only VBA macros but also an Object Linking and Embedding (OLE) object are embedded in the document. To find out how the OLE object is used and how the malware infection happens, we analyzed the VBA macros using Word’s developer tools.
Figure 2 – Output from oledump showing the VBA macro in the Word document.
The VBA code is distributed over several different modules inside the document and is executed by the Document.Open event. The OLE object is then saved with a “.tmp” file extension into one of the local temp folders under “C:\Users\[username]\AppData\Local\Temp”. As the VBA code does not know where the file was stored, it then recursively searches through all local temp folders.
Figure 3 – VBA macro which moves the tmp file to the templates folder as a DLL.
Once the “.tmp” file is found, it is moved and renamed to the Office templates folder (C:\Users\username\AppData\Roaming\Microsoft\Templates) as “W0rd.dll” and loaded using rundll32.exe. As a second argument, the macro passes the entry function “DllUnregisterServer” to rundll32.exe so that the execution starts correctly.
Figure 4 – VBA macro which runs rundll32.exe to load the malware.
Packed DLL analysis
Briefly looking at the DLL characteristics shows that there are two unknown sections, which could be an indicator of packing being used to obfuscate the malware. Opening the DLL in a debugger and running through the program, focusing on what is happening with the suspicious sections confirms that there is indeed some sort of unpacking happening.
Figure 5 – Sections of the PE file (“W0rd.dll”).
Although the unpacking procedure happens in multiple steps, it can be described in two broad stages:
Decryption Stage 1
First, the malware allocates new memory which is used to copy the data from section “.rdata4” into it. The data, however, is not copied identically from the section to the new memory region because the bytes containing 0x21 are omitted. As soon as the copy operation is finished, the decryption process starts. The first four bytes at the beginning of the newly allocated memory indicate the length of the data that will be decrypted. The algorithm to decrypt the data is simple. It uses an XOR operation with the key and plaintext being incremented after each four-byte operation. To start, the key is initialized with 0xD508. A replication of this algorithm, written in Python, can be found in our GitHub repository.
Figure 6 – Data view of the section containing the encrypted malware.
Looking at the decrypted data and the behavior of the program, we can see that there are multiple areas containing different types of information. The names of Windows API functions are stored in the first 150 bytes. The area after this contains encrypted data. Finally, the executable code used to decrypt the encrypted data is located at the end of the section. Figure 7 shows the structure of the memory section.
Figure 7 – Structure of the encrypted section.
The API function located at the beginning of the memory section are resolved using GetProcAddress. However, instead of being resolved within kernel32.dll, they are resolved in kernelbase.dll. This is important to note because when debugging Hancitor samples, breakpoints are most commonly set on functions from kernel32.dll and thus would not be triggered during execution. After resolving the functions, the second decryption stage occurs.
Decryption Stage 2
As indicated, the decrypted memory structure contains executable code. As expected, the instruction pointer jumps directly to this section, which also contains the decryption algorithm for the second stage. Before the decryption starts, new memory is allocated and the encrypted data from stage 1 is copied to it. The decryption algorithm of stage 2 is generally the same, but uses 0x3E9 as the initialization key. The output of this decryption leads us to a PE file.
Figure 8 – Overview of Hancitor’s decryption procedure.
The copy procedure is done section by section to bring the executable into the loaded form. This technique is called self-injection or PE overwrite. To make the new image runnable, several Windows API functions are resolved using GetProcAddress and directly patched into the memory of the loaded executable. These function addresses vary from installation to installation, so this patching cannot be done by a static unpacker. For all the other decryption procedures described, you can find a static unpacker script in our GitHub repository. To effectively run the new payload, a return to the correct DLL entry point is made. It is important to note that the AddressOfEntryPoint in the optional header does not match the exported functions DllRegisterServer or DllUnregisterServer and it is necessary to run one of the exported functions to start the malware. When using x32dbg to analyze the sample, simply patching the AddressOfEntryPoint to one of the exported functions makes the DLL runnable.
Running Hancitor Malware
As soon as the unpacked executable is running, the malware gathers information about the infected system. The following disassembly shows calls to multiple functions used to collect the information.
Figure 9 – x86 disassembly of Hancitor’s information gathering function.
First, the malware calls a function we named “getComputerInfo”. This function obtains the username, the computer name and the domain of infected system. The subsequent functions collect additional information such as the machine’s public IP address, domain trust information and the computer architecture. The malware identifies the computer’s public IP address by making a HTTP GET request to “hxxp://api.ipify[.]org”, a free public IP address API. All the collected information is then put together into a query string which is generated based on the computer architecture.
Figure 10 – Query string containing system information before being sent to the C2.
To determine the command and control (C2) servers waiting for the data to be sent to, the malware calls a decryption function that uses the RC4 algorithm to get a list of potential C2 URLs.
Figure 11 – URL and build decryption function.
After successfully decrypting the C2 URLs, the data is sent there using a HTTP POST request adding the constructed query string as data. To increase the probability of reaching an active server, the malware iterates over all the decrypted C2 URLs and tries to reach all of them until one of them sends a response.
Figure 12 – C2 communication function.
We assume that based on the received data the C2 server responds with either a simple string which can be decrypted to an active malware download server or with garbage data in the form of a simple string. Although the decoding algorithm of the C2 response looks quite complex, it is actually Base64 decoding, followed by an XOR operation using the key 0x7A. If the decryption leads to a valid URL, the malware initiates a download, which delivers an executable. To execute the binary, Hancitor uses one of the following techniques:
- Create Process
- Create Thread
- Process Hollowing
- Thread Execution Hijacking
If the method “Create Process” is chosen, then the malware writes the retrieved executable to disk into the temp folder and executes it using rundll32.exe with “start” as the argument for the entry function.
The Create Thread method is as straightforward as Create Process. The malware simply allocates some memory, writes the malware into it and creates a new thread from it.
If the Process Hollowing method is used, a new svchost.exe process is created in a suspended state. The malware then allocates new memory in the newly-created process, writes the executable to it and executes it in a new thread.
Figure 13 – Process creation function.
Thread Execution Hijacking
The final execution method Hancitor supports is Thread Execution Hijacking. This method is mostly the same as the above described Process Injection method. The only difference is that the malware replaces the thread context with the downloaded executable and resumes it afterwards.