/* CAT(1) */

By Jeff White (karttoon)

One thing I've noticed lately while analyzing PowerShell attacks is that no one is doing much in the way of argument obfuscation. The attacks focus primarily on their end payload, or the delivery mechanism, and use PowerShell simply as their vessel to launch their evil code. At most I see some tools randomizing case or, over the course of iterations, the developers have shortened arguments but nothing really useful.

To illustrate, I'm going to pick on Magic Unicorn (because it rocks) and show how the arguments used to launch PowerShell have changed.

3eda35e: full_attack = "powershell -noprofile -windowstyle hidden -noninteractive -EncodedCommand " + base64 922c34f: full_attack = "powershell -nop -wind hidden -noni -enc " + base64 a18cb5d: full_attack = "powershell -nop -win hidden -noni -enc " + base64

Not a whole lot of change over a two year period: no change of case, static argument positioning, and just a shortening of the used arguments.

If you check out another popular tool, PowerSploit, you can see how they approach building the arguments to launch their PowerShell payloads.

# Build the command line options # Use the shortest possible command-line arguments to save space. Thanks @obscuresec for the idea. $CommandlineOptions = New-Object String[](0) if ($PSBoundParameters['NoExit']) { $CommandlineOptions += '-NoE' } if ($PSBoundParameters['NoProfile']) { $CommandlineOptions += '-NoP' } if ($PSBoundParameters['NonInteractive']) { $CommandlineOptions += '-NonI' } if ($PSBoundParameters['WindowStyle']) { $CommandlineOptions += "-W $($PSBoundParameters['WindowStyle'])" }

Again, no argument position randomization since they join the arguments as they are built; however, you have the potential to include or exclude various arguments based on your need, which of course will make it less static. It's slightly better than Magic Unicorn in that respect.

Soooo...what? Who cares and why is this relevant?

It's relevant because when you know an attackers tool-of-choice, at best you may be able to create point-defenses to stop them but, at worst, you at least get an insight into the attackers tool set and capabilities. With either end of the spectrum, it's good information to have when thinking about what step to take next during analysis or response.

Now, most PowerShell attacks that I see are delivered through malicious Microsoft Office documents containing macros that launch PowerShell OR through generated binaries that are simply designed to execute the commands. I've seen a lot of effort go into obfuscating macros and a lot of work go into the actual PowerShell payloads but I assume most people look at the arguments and don't think much about this middle link. It's so inconsequential to the overall attack but it does provide a perfect place for analysts and defenders to profile or identify the code.

Ok, but how unique are these argument strings?

To use the two tools from above, if I Google each of their respective strings...

First (oldest) Magic Unicorn: 58 hits "-noprofile -windowstyle hidden -noninteractive -EncodedCommand" Second Magic Unicorn: 150 hits "-nop -wind hidden -noni -enc" Third (newest) Magic Unicorn: 447 hits "-nop -win hidden -noni -enc" PowerSploit: 41 hits "-NoP -NonI -W Hidden -E"

It's relatively trivial to go from one of those lines, which get generated as process activity in every sandbox under the sun, to a small set of hits on Google. When used with additional contextual information (e.g. payload or delivery mechanism) you can try to narrow in faster on the tool. It's not rocket science and, for it to actually be useful, it requires at least enough arguments to stand out from someone just running, for example, "-encodedcommand".

In my experience, I've found these argument patterns to be very helpful and use them quite frequently during analysis. This, of course, now brings me to the point of the blog - a new tool I put together called argfuscator which attempts to address the issues I mentioned previously.

Specifically, it will randomly adjust lengths of each argument, randomize case in arguments, randomize case in values (sans base64 in "encodedcommand"), randomize caret injection for further command-line obfuscation (sans values provided to "command"), and finally randomize the argument positions. There is enough variety that it creates fairly unique strings each time.

Using the same four strings as before, but now running them through the tool.

$ python argfuscator.py "powershell.exe -noprofile -windowstyle hidden -noninteractive -EncodedCommand ZQBjAGgAbwAgACIAVwBpAHoAYQByAGQAIgA=" pOwErsheLL.EXe -e^nco^d^e^dc ZQ^BjAGg^A^bw^AgA^C^IA^V^w^B^pA^H^oAYQ^B^yAG^Q^AI^g^A^= -Wi^N^do hI^dDE^N -n^OnIN^t -n^O^P^R $ python argfuscator.py "powershell.exe -nop -wind hidden -noni -enc ZQBjAGgAbwAgACIAVwBpAHoAYQByAGQAIgA=" pOwERSHElL.Exe -encodedcommand ZQBjAGgAbwAgACIAVwBpAHoAYQByAGQAIgA= -WI^N^doWS H^I^d^DEn -n^op^rO^f -nONInTeRAcTiVe $ python argfuscator.py "powershell.exe -nop -win hidden -noni -enc ZQBjAGgAbwAgACIAVwBpAHoAYQByAGQAIgA=" powerShELl.exe -Wi hiDDEn -n^oPRoF -ec ZQ^B^jA^G^g^A^bwAg^ACIA^VwBp^AH^o^AYQ^B^y^AGQ^AI^g^A= -NONInTeRaCTiVe $ python argfuscator.py "powershell.exe -NoP -NonI -W Hidden -E ZQBjAGgAbwAgACIAVwBpAHoAYQByAGQAIgA=" p^O^wE^R^s^hELl.^EXe -e ZQB^jA^GgAbwAg^A^C^I^A^VwB^pA^H^o^AYQ^By^AG^QAI^gA^= -w^iN^d^o^Ws^t h^i^dD^eN -NoninteRActIv -NOprofilE

I've tested the script using various custom PowerShell commands, along with regenerating ones I've seen in the wild, and it all seemed to work or I ironed out the bugs. I'm sure it's not perfect and there are certain areas that could use improving but I think it's a decent start that can provide value for the offensive teams out there.

Sometimes it's the little things...

The code is available on GitHub.




Older posts...