Cerbero Suite: The Hacker’s Multitool
We would like to thank InQuest for this interesting malware sample: it’s a great sample to show the power of Cerbero Suite!
- MD5: 59C38D612200A9FDE900366872C1F051
- SHA-1: 478454F501C1AD52F3D31E52D54DA514442E83C6
- SHA-256: 6DD6C65DA87CE383B9B0D6CA39CFD76C90F6D65B4C09CFC88352ED60EC96809A
The first thing we notice when opening the malicious document with Cerbero Suite is that it contains VBA code. If we glance over the code, we reach an interesting part.
This part of code dumps a VBE script to disk and executes it. VBE files are encoded VBS scripts and Cerbero Suite automatically decodes these scripts into readable VBS code.
In order to find the encoded script, we go to the “sdghfgjfgkgkghk.o” stream. If you don’t know where the encoded script begins, you can just advance the cursor in the hex view and keep on pressing “Ctrl+E” until Cerbero automatically detects the encoded script.
Once we find the start of the VBE script, we press “OK” to load add the embedded object. Now we can inspect the child VBE object! As already mentioned, Cerbero automatically decodes the file so that we can analyze the VBS code.
We notice that the VBS code contains a very big string which looks like base64.
ewfwegwh = "VFZxUUFBTUFBQUFFQUFBQS8vOEFBTGdBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEwQUFBQUE0ZnVnNEF0QW5OSWJnQ" + _
"lRNMGhWR2hwY3lCd2NtOW5jbUZ0SUdOaGJtNXZkQ0JpWlNCeWRXNGdhVzRnUkU5VElHMXZaR1V1RFEwS0pBQUFBQUFBQUFEeXFwUVF0c3Y2UTdiTCtrTzJ5L3BEZGNTblE3dk" + _
"wra08yeS90RE1NdjZRM1hFcEVPM3kvcERkY1NsUTYzTCtrTjF4S0JEdDh2NlExSnBZMmkyeS9wREFBQUFBQUFBQUFBQUFBQUFBQUFBQUZCRkFBQk1BUU1BelZFQ1NBQUFBQUF" + _
"BQUFBQTRBQVBBUXNCQndvQW1nQUFBSDREQUFBQUFBQmNaQUFBQUJBQUFBQ3dBQUFBQUFBQkFCQUFBQUFDQUFBRkFBRUFCUUFCQUFRQUFBQUFBQUFBQUZBRUFBQUVBQUMzd1FR" + _
"QUFnQUFoQUFBQkFBQUVBQUFBQUFRQUFBUUFBQUFBQUFBRUFBQUFBQUFBQUFBQUFBQWdKMEFBSXdBQUFBQTBBQUFPSGtEQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ" + _
"UFBREFTQUFBY0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQXdBZ0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU" + _
"FBQUFBQUFBQUFMblJsZUhRQUFBREltUUFBQUJBQUFBQ2FBQUFBQkFBQUFBQUFBQUFBQUFBQUFBQUFJQUFBWUM1a1lYUmhBQUFBNUJzQUFBQ3dBQUFBQkFBQUFKNEFBQUFBQUF" + _
"BQUFBQUFBQUFBQUVBQUFNQXVjbk55WXdBQUFBQ0FBd0FBMEFBQUFIb0RBQUNpQUFBQUFBQUFBQUFBQUFBQUFBQkFBQUJBc3FBQ1NFQUFBQUFzb1FKSVRRQUJBQ3loQWtoYUFB" + _
....
Following the huge base64 string, there are some lines of code which perform transformations on the string and dump the results to disk. We could use filters in Cerbero Suite to perform the same transformations and then decode the base64 string as a child object, but in this case it’s easier to just copy/paste the VBS code and let it decode the string.
ewfwegwh = [STRING]
ewfwegwh = Replace(ewfwegwh, Chr(45), Chr(43))
ewfwegwh = Replace(ewfwegwh, Chr(95), Chr(47))
Select Case (Len(ewfwegwh) Mod 4)
Case 0: ewfwegwh = ewfwegwh
Case 2: ewfwegwh = ewfwegwh + Chr(61) & Chr(61)
Case 3: ewfwegwh = ewfwegwh + Chr(61)
End Select
pfkewfnnwg = gewgsdrtyutyk(ewfwegwh)
pqwkdaiffewfgwerheejjej = gewgsdrtyutyk(pfkewfnnwg)
Function gewgsdrtyutyk(vsdvjtktk)
Const KMOgsBIDf = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
Dim rgfdb, sOut, groupBegin
vsdvjtktk = Replace(vsdvjtktk, vbCrLf, "")
vsdvjtktk = Replace(vsdvjtktk, vbTab, "")
vsdvjtktk = Replace(vsdvjtktk, Chr(32), "")
rgfdb = Len(vsdvjtktk)
If rgfdb Mod 4 <> 0 Then
Exit Function
End If
For groupBegin = 1 To rgfdb Step 4
Dim numDataBytes, CharCounter, thisChar, thisData, nGroup, pOut
numDataBytes = 3
nGroup = 0
For CharCounter = 0 To 3
thisChar = Mid(vsdvjtktk, groupBegin + CharCounter, 1)
If thisChar = Chr(61) Then
numDataBytes = numDataBytes - 1
thisData = 0
Else
thisData = InStr(1, KMOgsBIDf, thisChar, vbBinaryCompare) - 1
End If
If thisData = -1 Then
Exit Function
End If
nGroup = 64 * nGroup + thisData
Next
nGroup = Hex(nGroup)
nGroup = String(6 - Len(nGroup), Chr(48)) & nGroup
pOut = Chr(CByte(Chr(38) & Chr(72) & Mid(nGroup, 1, 2))) + _
Chr(CByte(Chr(38) & Chr(72) & Mid(nGroup, 3, 2))) + _
Chr(CByte(Chr(38) & Chr(72) & Mid(nGroup, 5, 2)))
sOut = sOut & Left(pOut, numDataBytes)
Next
gewgsdrtyutyk = sOut
End Function
Set fs = CreateObject("Scripting.FileSystemObject")
Set a = fs.CreateTextFile("malware.bin", True)
a.WriteLine(pqwkdaiffewfgwerheejjej)
a.Close
We execute our VBS script and after a bit of time we’ll have our “malware.bin” payload on disk. When we open the payload we can see that it claims to be the “Cabinet Self-Extractor” by Microsoft. By quickly looking at the code of an original “wextract.exe” binary, we can confirm that the file seems authentic.
Looking at the “Hierarchy” view, we can see that Cerbero already found the CAB file to extract in the resources of the binary and lets us inspect its contents. However, we also need to know what the self-extractor does with the files once extracted. So we take a look at the assembly code of the binary in Cerbero Suite.
We notice that the disassembled code and its decompiled counter-part contain a lot of calls to access the resources of the binary.
So we switch to the resources of the Portable Executable and notice the “RUNPROGRAM” resource (the “CABINET” resource is the one which contains the CAB file).
The “RUNPROGRAM” resource contains the string executed after having extracted the contents of the cabinet file:
cmd /ccmd /cHELP&help&cmd /cru..................................jse&help&exit
What it does is to execute the "ru..................................jse"
file. So we take a look at that file inside the cabinet.
JSE files are the equivalent of VBE files: they are encoded JS files. However, they are not browser JavaScript files, but WScript files, meaning that they have at their disposal the same APIs as VBS scripts and therefore have access to the entire system.
Again, Cerbero Suite automatically decodes the JSE file for us.
The first thing we notice is that the script is lacking new-lines and is therefore completely unreadable. The first operation we perform is to beautify the code by running an action: we press “Ctrl+R” and then click on “Beautify JavaScript”.
The code immediately becomes easier to read.
However, the code is heavily obfuscated and consists of almost 50000 lines of unreadable JavaScript. We need to de-obfuscate it! In the obfuscated JavaScript we can see a repeated use of the following lines of code:
try
{
Jer56fh -= 0.7;
Jer56fh();
}
catch (Jer56fh)
{
Jer56fh += 0.82;
};
These lines do absolutely nothing, so we can remove them with a single regular expression.
s = re.sub(r"try\s*{\s*Jer56fh\s-=\s[0-9.;]+\s+Jer56fh[(][)][;]\s*}\s*catch [(]Jer56fh[)]\s*{\s*Jer56fh [+][=] [0-9.;]+\s*};", "", s)
Already this reduces the dimensions of the obfuscated JavaScript significantly. Now we can see that the most used construct in the code is the following:
(function(jhwes4)
{
jhwes4[Ju67gh] = 0;
jhwes4[Kio87.Ju67gh + Kio87.FiLo7] = 108;
return PjSbWnR(PjSbWnRW() + (jhwes4[Hr6gt] + jhwes4[Ju67gh]), fertu);
})(Nu0o.a ...
This inline function does nothing else than to compute a string character. It sums the value of "jhwes4[Ju67gh]"
and "jhwes4[Kio87.Ju67gh + Kio87.FiLo7]"
and calls the JavaScript function "fromCharCode"
on the result.
Thus, what we do is to use another regular expression to find all instances of this type of code and convert them into strings containing a single character.
s = re.sub(r"[(]function[(][a-zA-Z0-9]+[)]\s*{\s*[a-zA-Z0-9]+[[][a-zA-Z0-9]+[]] = ([0-9]+);\s*[a-zA-Z0-9]+[[][a-zA-Z0-9+ .]+[]] = ([0-9]+);\s*return PjSbWnR[^;]+;\s*}[)][(]Nu0o[.]a[^)]*[)]", \
lambda m: "'" + chr(int(m.group(1)) + int(m.group(2))) + "'", s)
At this point the code is already much more readable, but we got a lot of expressions such as: 's' + 't' + 'r'
. We want to simplify these expressions into single strings with yet another regular expression.
s = re.sub(r"('[^']'[ ]?[+]?[ ]?)+('[^']')", lambda m: '"' + eval(m.group()) + '"', s)
Now the JavaScript code is absolutely readable! As a last touch, we replace some garbled variable names with their readable aliases.
aliases = (
("dtXmUvery59", "WScript"),
("dtXmUrelated34", "ActiveXObject"),
("dtXmUform61", "WScript.ScriptFullName"),
("dtXmUwith55", "FileSystem"),
("dtXmUtheorem3", "ShellApp")
)
for (a, b) in aliases:
s = s.replace(a, b
If you want to do the deobfuscation yourself, just press “Ctrl+Alt+R” while on the view of the obfuscated JavaScript code and then paste the following Python code.
from Pro.UI import proContext import re s = proContext().getCurrentView().getText() # # use a regex to remove bogus clauses such as: # # try # { # Jer56fh -= 0.7; # Jer56fh(); # } # catch (Jer56fh) # { # Jer56fh += 0.82; # }; # # s = re.sub(r"try\s*{\s*Jer56fh\s-=\s[0-9.;]+\s+Jer56fh[(][)][;]\s*}\s*catch [(]Jer56fh[)]\s*{\s*Jer56fh [+][=] [0-9.;]+\s*};", "", s) # # some logic to convert this syntax into a character # # (function(jhwes4) # { # # jhwes4[Ju67gh] = 0; # jhwes4[Kio87.Ju67gh + Kio87.FiLo7] = 108; # return PjSbWnR(PjSbWnRW() + (jhwes4[Hr6gt] + jhwes4[Ju67gh]), fertu); # })(Nu0o.a # <- more bogus parameters may follow # s = re.sub(r"[(]function[(][a-zA-Z0-9]+[)]\s*{\s*[a-zA-Z0-9]+[[][a-zA-Z0-9]+[]] = ([0-9]+);\s*[a-zA-Z0-9]+[[][a-zA-Z0-9+ .]+[]] = ([0-9]+);\s*return PjSbWnR[^;]+;\s*}[)][(]Nu0o[.]a[^)]*[)]", \ lambda m: "'" + chr(int(m.group(1)) + int(m.group(2))) + "'", s) # # now simplify all 's' + 't' + 'r' expressions # s = re.sub(r"('[^']'[ ]?[+]?[ ]?)+('[^']')", lambda m: '"' + eval(m.group()) + '"', s) # # replace a few aliases # aliases = ( ("dtXmUvery59", "WScript"), ("dtXmUrelated34", "ActiveXObject"), ("dtXmUform61", "WScript.ScriptFullName"), ("dtXmUwith55", "FileSystem"), ("dtXmUtheorem3", "ShellApp") ) for (a, b) in aliases: s = s.replace(a, b) print(s)
This script prints out the deobfuscated JavaScript which is now only 900 lines of code!
Among various things, the JavaScript code seems to download another JSE script from a URL, but when we tried to access the remote file we were unable to. So we stop here our write-up.
We hope you enjoyed our analysis!
Free On-Demand Webinar: Think Before You Click
Whether sent as an email attachment, sitting in your cloud or traversing the Web, file-borne threats have become a proven favorite for delivering malware and phishing campaigns. View our webinar on-demand and get firsthand tips about how to safeguard your cybersecurity stack with File Detection and Response (FDR) and stop file-borne threats in their tracks.