TrickBot: A Closer Look
In early November, the Cybersecurity and Infrastructure Security Agency (CISA) released an advisory warning administrators in the healthcare and public sector that TrickBot is being used to disturb healthcare services by launching ransomware attacks and by stealing data. This month, Threat Simulator released a TrickBot assessment covering the malware's kill chain. In this post, we'll take a close look at the installation phase of the TrickBot infected document that inspired the assessment.
Process tree for the sample under analysis.
Sample.doc Analysis (SHA-1: c2f948d866ff4dfa8aaebda5507c7d606ac9fb28)
The sample is a .doc file, an older file type for Microsoft Word, also known as Microsoft Word 97-2003 format. This file type may contain Visual Basic for Applications (VBA) macros.
The document convinces the target to click Enable Editing and Enable Content. This is common for malicious macro enabled documents to bypass security prompts and run the macro code embedded within it.
The document contains the Document_Close event procedure. Upon closing of the document, the Document.Close event will fire and the Document_Close procedure will be called. This will evade sandboxes that do not close the document during analysis.
The Document_Close procedure will delay execution for 2 seconds and then proceed to call the function ResetCalcD. ResetCalcD will call another function named UniqueValues.
The UniqueValues function will first create the directory "C:\Artrite\Final_Joana\"
Then, UniqueValues will create the file "C:\Artrite\SarilumabSAR153191.part" and fill it with VBScript comments.
Finally, UniqueValues will create the file "C:\Artrite\SarilumabSAR153191.vbe" and fill it with VBScript comments along with the value of the caption "luinpedrnass.dados.Caption." The caption contains the next stage payload, a VBScript file.
After the call to ResetCalcD, the Document_Close procedure will create an Excel.Application object. As a result, svchost.exe will spawn a process for excel.exe. This will mask the calling process, winword.exe in this case, and will make tracking the process tree and kill chain of the malware more difficult.
Next, the DisplayAlert property is set to False. This will prevent UI pop-ups from being presented to the user.
Finally, the DDEInitiate method is called. This method will launch an application if the target system has the Dynamic Data Exchange Server Launch Trust Center setting enabled. This setting is no longer enabled by default.
If configured to do so, DDEInitiaite will cause excel.exe to launch cmd.exe with the command-line:
Finally, wscript.exe will execute the next stage, C:\Artrite\SarilumabSAR153191.vbe.
tl;dr: The malicious document will use the Document_Close VBA macro to drop and execute a VBE file upon closing the document.
The script file contains double base64 encoded data in a variable named tData.
tData is decoded using the function DecodeBase64_1.
DecodeBase64_1 uses the Microsoft.XMLDOM object to decode base64 encoded data and uses the Adodb.Stream object to write the decoded contents to “C:\Artrite\Final_Joana\WhatAreTopFacts.rtc”
There is minor obfuscation using the Chr function to hide the strings "b64" and "bin.base64"
The data is then decoded a second time with a similar base64 decoding function and once again saved to “C:\Artrite\Final_Joana\WhatAreTopFacts.rtc”
Finally, an Excel DDE is used once again to launch the next stage, WhatAreTopFacts.rtc (a 32-bit DLL file), using rundll32.exe
tl;dr: SarilumabSAR153191.vbe will drop and execute a 32-bit DLL file using rundll32.exe.
WhatAreTopFacts.rtc is a DLL that exports the function DllRegisterServer.
It is odd that the malware author chose to name the exported function DllRegisterServer while not taking advantage of the LoLBins that utilize that exported function. (msiexec.exe, odbcconf.exe)
The DllRegisterServer function will deobfuscate the strings "LdrFindResource_U" and "LdrAccessResource".
Next, DllRegisterServer will dynamically resolve the API functions ntdll!LdrFindResource_U and ntdll!LdrAccessResource before calling LdrFindResource_U and LdrAccessResource to fetch the contents of a resource embedded within the resource section of the binary.
The embedded resource has an entropy value of 7.99613 bits per byte. The high entropy suggests that the resource is encrypted data.
DllRegisterServer will then copy the resource data into freshly allocated PAGE_EXECUTE_READWRITE memory.
DllRegisterServer will go onto decrypt the resource data using a dynamically derived key and an XOR based encryption/decryption routine.
Finally, DllRegisterServer will execute the decrypted resource data. The resource data turns out to be encrypted shellcode.
tl;dr: WhatAreTopFacts.rtc will decrypt and execute encrypted shellcode embedded as a resource.
WhatAreTopFacts.rtc Shellcode Analysis
At the tail end of the shellcode there is an embedded Portable Executable (PE) file. The embedded PE is a DLL.
The shellcode begins by using the (JMP)/CALL/POP technique to get the base address of the shellcode. The base address is then used to calculate the start and end address of the embedded PE.
In the shellcode, there is a function that gets a pointer to the PEB and walks the linked list of loaded modules.
In the same function, the ror instruction is used within a loop.
This function implements a common shellcode technique that resolves Windows API functions by using a precomputed value using a ROR 13 based hash function.
The shellcode will then use the above function to resolve the APIs necessary to load a PE from memory.
These APIs will be used to load the PE in memory.
tl;dr: The shellcode will load and execute a DLL from memory.
WhatAreTopFacts.rtc Embedded DLL 1 Analysis
There is an embedded PE within this DLL. The embedded PE is a DLL.
First, this DLL dynamically resolves the API function kernel32!GetNativeSystemInfo.
Next, the DLL parses the embedded PE's headers and calculates the PE’s size.
Afterwards, VirtualAlloc is used to allocate memory at the PE's preferred base address. If memory allocation fails, then memory is allocated again, this time letting the OS decide the allocated memory address.
Next, the DLL allocates heap memory for a custom struct and initializes it.
Next, the DLL copies the PE's headers into the allocated memory region.
The headers are then used to load the PE's sections into memory.
The DLL will then go onto perform base relocation, if necessary.
Next, the libraries in the PE's import table will be loaded.
Afterwards, the image base address in the PEB is set to the base address of the next stage PE.
Finally, the entry point of the next stage PE will be called.
This DLL is a reflective loader.
The custom struct from earlier can be used to find the source of this reflective loader implementation. Googling the following will lead to a fork of the MemoryModule project:
The simularity struct definitions suggests that this DLL uses a derivative of the MemoryModule project.
Struct definition from MemoryModule
Reversed struct definition
The only significant differences between reflective loader implementations were:
- A custom implementation of the C Run-time Library's (CRT) realloc function is used. This is a necessary since the CRT's realloc function requires that the CRT is initialized, which it will not be in this case.
- GetNativeSystemInfo is dynamically resolved instead of imported
- The image base addresses in the PEB is updated
tl;dr: This DLL will load and execute the next stage DLL from memory using MemoryModule.
WhatAreTopFacts.rtc Embedded DLL 2 Analysis
This DLL is similar but slightly different to the DLL from the previous stage. The custom struct no longer has a field for VirtualAlloc and VirtualFree. This correlates with revisions of MemoryModule prior to commit d88817fb.
It is odd that two different versions of the same project are used within the same sample.
The next stage DLL is launched by calling its DllRegisterServer exported function.
tl;dr: This DLL will load and execute the next stage DLL from memory using MemoryModule (again).
WhatAreTopFacts.rtc Embedded DLL 3 Analysis
First, the DLL will allocate PAGE_EXECUTE_READWRITE memory using obfuscated values for the constants: MEM_COMMIT and PAGE_EXECUTE_READWRITE.
Then, encrypted shellcode is decrypted using an XOR based encryption/decryption routine.
After decryption, the shellcode will be executed using the API function CreateThread.
Finally, the DLL waits 3 seconds for the shellcode to finish before exiting the rundll32 process.
tl;dr: this DLL will decrypt and execute shellcode using the CreateThread.
WhatAreTopFacts.rtc Embedded DLL 3 Shellcode Analysis
In the last part of the installation phase, self-unpacking shellcode is used to create a new 64-bit wermgr.exe process in the suspended state using kernel32!CreateProcessInternalW.
Then, the shellcode transitions the current 32-bit process (rundll32.exe) context into a 64-bit context. This context switch will bypass popular API monitoring tools that only hook 32-bit ntdll APIs for WoW64 processes.
After switching context, code is injected into the suspended process using the Process Hollowing technique.
Finally to complete installation, the main thread of the wermgr.exe process is resumed.\