Wednesday, 21 October 2015

Deobfuscating malware droppers written in VBScript

Once in a while I run across malware that drops itself via a macro embedded into a Microsoft Word DocX file, written in Visual Basic script. These payloads are fairly common and have been documented in a number of places. However, I noticed in one instance that the payload it was retrieving was encoded somehow with the macro doing the decoding.

If you're not sure what the document I am referring to looks like, here's a screenshot of what you should expect if you were to open it in Word or LibreOffice.

I've opted to not share the whole source code for the payload here but I am writing this as a primer for retrieving the data should you be interested in it. I've removed references to the keys and location of the payload but again this writeup should provide more than enough information.

It's pretty straightforward to decipher what the URL is so you can download the payload. It will look a lot like this when you do so:
IsDwQV = "httEeDxPbOZhstcWp://"
dlBSaKVPUZeUffK = Replace(IsDwQV, "EeDxPbOZhstcW", "")

vJPIYmKkzEidc = dlBSaKVPUZeUffK + "" + "file.da" + "t"
As we can see, the URL is really "" so all one has to do is retrieve it normally and have the payload. This isn't new to this type of attack, but what is different here is that you'll need to look for an additional line to decode the file. An example of what we're looking for is here:
PTIEIYzefrUBrv.Write auRPAIQxRBuNVNs(ZlOton(AsWLAJsjgp), "mal" + "wa" + "rek" + "ey")
Again, just as straightforward as earlier, we just need to combine the second argument in this function to form the key "malwarekey".

Now that we've gone and figured out the payload's URL and the key, we'll want to see how the payload is decoded. It goes through two processes: the first where reorders the contents of the file and the second where it performs a XOR on each byte.

The reordering function looks a lot like this (keep in mind, the variables and function names will change to avoid detection but the patterns will remain mostly the same):
Function auRPAIQxRBuNVNs(gZZoRIEiqkagc, CIKkGOaWM)
Dim vJPIYmKkzEidc
vJPIYmKkzEidc = ""
Dim yjiyoPGJqpm
yjiyoPGJqpm = 2 - 1
Dim RpKxIaBse
RpKxIaBse = 1
For RpKxIaBse = 1 To Len(gZZoRIEiqkagc)
PhnHyZVCyES = Mid(CIKkGOaWM, yjiyoPGJqpm, 1)
vJPIYmKkzEidc = vJPIYmKkzEidc & Chr(Asc(Mid(gZZoRIEiqkagc, RpKxIaBse, 1)) Xor Asc(PhnHyZVCyES))
yjiyoPGJqpm = yjiyoPGJqpm + 1
If Len(CIKkGOaWM) < yjiyoPGJqpm Then yjiyoPGJqpm = 1

End Function
The XOR function then will look like this:
Function ZlOton(ODkdfygTwl)
Dim XvZDYBA, ZazVWW, SyyWJefcxs, eauVLHixkVU, cQdAHb, WGHeGPbgR
Dim myjfHUNidfOgtQ
ZazVWW = (&H3EF + 2892 - &HF3A)
SyyWJefcxs = (&H3EF + 2892 - &HF3A)
myjfHUNidfOgtQ = LenB(ODkdfygTwl)
Do While XvZDYBA <= myjfHUNidfOgtQ
WGHeGPbgR = WGHeGPbgR & Chr(AscB(MidB(ODkdfygTwl, XvZDYBA, 1)))
SyyWJefcxs = SyyWJefcxs + 1
If SyyWJefcxs > 300 Then
cQdAHb = cQdAHb & WGHeGPbgR
WGHeGPbgR = ""
SyyWJefcxs = (&H3EF + 2892 - &HF3A)
ZazVWW = ZazVWW + 1
If ZazVWW > 40 * (&H20 + 1142 - &H491) Then
eauVLHixkVU = eauVLHixkVU & cQdAHb
cQdAHb = ""
ZazVWW = 1
End If
End If
ZlOton = eauVLHixkVU & cQdAHb & WGHeGPbgR
End Function
The reorder function is easy to clean up, so I've gone ahead and written it like so:
Function reorder(filedata)
Dim var1, var2, var3, var4, var5, var6
var1 = 1
var2 = 1
var3 = 1
Do While var1 <= LenB(filedata)
var6 = var6 & Chr(AscB(MidB(filedata, var1, 1)))
var1 = var1 + 1
var3 = var3 + 1
If var3 > 300 Then
var5 = var5 & var6
var6 = ""
var3 = 1
var2 = var2 + 1
If var2 > 200 Then
var4 = var4 & var5
var5 = ""
var2 = 1
End If
End If
reorder = var4 & var5 & var6
End Function
Once we've cleaned this all up we can now determine that the function does absolutely nothing and is there to really obfuscate it further. The data that goes through this function comes out as the same, so it's really just a time-waster. However, the data is still encoded so I did go ahead and clean up the second function as so:
Function decodexor(filedata, filekey)
Dim var1
var1 = ""
Dim var2
var2 = 2 - 1
Dim var3
var3 = 1
For var3 = 1 To Len(filedata)
var4 = Mid(filekey, var2, 1)
var1 = var1 & Chr(Asc(Mid(filedata, var3, 1)) Xor Asc(var4))
var2 = var2 + 1
If Len(filekey) < var2 Then var2 = 1

decodexor = var1
End Function
Okay. So this code does in fact do something and now tells us that it's a straightforward XOR of the data. We can now just rewrite this script into Python line to line.

I've made it available via this Github Gist and per below:
from sys import argv

filename = argv[1]
malwarekey = argv[2]

def dexor(filedata, filekey):
    var1 = ''
    var2 = 0
    var4 = ''
    for x in xrange(0, len(filedata)):
        var4 = filekey[var2]
        var1 = var1 + chr(ord(filedata[x]) ^ ord(var4))
        var2 += 1
        if var2 >= len(filekey):
            var2 = 0
    return var1

if __name__ == '__main__':
    data = open(filename, 'rb').read()
    print dexor(filedata=data, filekey=malwarekey)
You'll want to ignore the fact that this Python function is really a terrible mirror copy of the original, but works one-to-one like the original VBScript; there are of course better ways to write this.

Once happy, we can run it like so:
$ python file.dat malwarekey > file.exe
$ file file.exe 
file.exe: PE32 executable (GUI) Intel 80386, for MS Windows
Now we have the file decoded and can execute it within whatever sandbox we'd like!

1 comment:

  1. Found a slightly different version today:

    Function decodexor(FileData, key)
    Dim Var1
    Var1 = ""
    Dim Var2
    Var2 = 2 - 1
    Dim Var3
    Var3 = 1
    For Var3 = 1 To Len(FileData)
    Var4 = Mid(key, Var2, 1)
    Var5 = Mid(FileData, Var3, 1)
    Var1 = Var1 & Chr(Asc(Var5) Xor Asc(Var4))
    Var2 = Var2 + 1
    If Len(key) < Var2 Then Var2 = 1

    decodexor = Var1
    End Function