Obfuscation rarely used

The first thing that caught our eye was that, even though there are many obfuscation tricks available for PowerShell and even automated tools that can obfuscate scripts for users, these are rarely used in the wild. Only four percent of the PowerShell command lines we analyzed tried to obfuscate themselves by using a mixture of lower- and uppercase letters. And even those that do are often auto-generated by some toolkit with a poor randomizer. The following are two examples that were embedded into Microsoft Office documents:

pOWErSheLl -nopRoFi -WIn hiDdeN -NOLo -NOnInteRA -eXeCUTIoNp bYpass […]

poweRSheLL -NoniNTeRACtivE -NoPr -exeCuTi ByPASS -WinDO hIDDen […]

Of course, the classical string rearranging with the “-f” function or string concatenation are also used in an attempt to fool simple pattern matching. In our test set, we saw it used by 3.2 percent of the samples:

[…] (. (\" {2}{0}{1}\" -f'-o','bject','new') (\"{1}{3}{5}{0}{2}{4}\" -f't','syst','.webclie','em','nt','.ne')).('d'+'ow'+'nloadfil'+'e')[…]

Isolated cases of other string manipulation or special characters like the tick do occur as well, but very rarely:

[TExt.ENCOdInG]::ascII')).repLACe(([chAR]118+[chAR]74+[chAR]100),[strinG][chAR]36).repLACe('p2j',[strinG][chAR]39).repLACe(([chAR]90+[chAR]111+[chAR]73),'|')[…]

$env:puBLIC[13]+$ENV:PubLic[5]+'X' […]

Occasionally there are PowerShell scripts generated by frameworks such as Invoke-Obfuscation resulting in cryptic scripts which make use of ConvertTo-SecureString and SecureStringToGlobalAllocUnicode.

powershell iEX(( [RuNTime.InteropsErviCEs.maRsHaL]::PTrTOsTRinGAUto( [rUNtImE.iNTERoPSERVIceS.marsHAL]::SecUReStriNGTOBSTR($('[REMOVED]' |ConVerTTO-secuREStrING -KEy (146..169)) ))))

Many attackers probably are not too concerned about obfuscation because they know that not everybody is monitoring PowerShell activity anyway. Even if the security personnel do, then a non-obfuscated command line might be more likely to slip unnoticed through the cracks. Too much obfuscation can be a red flag. Of course, another option for the attacker is to use a BASE64-encoded blob to hide their commands, resulting in an extra step of decoding required, before the payload can be seen. This is often done by all kinds of scripts, including benign ones.

From all analyzed scripts, 5.7 percent used a BASE64-encoded string to hide their commands. With 80 percent of this subset of scripts, most simply used the built-in “-EncodedCommand” command line argument or a variation thereof to decode and run their commands. But some attackers used other commands to achieve the same results, as there are usually many ways to reach a goal with PowerShell:

powershell.exe -noni -nop -w hidden -c &([scriptblock]::create((New-Object IO.StreamReader(New-Object IO.Compression.GzipStream((New-Object IO.MemoryStream(,[Convert]::FromBase64String('[…]’)

iex ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($funs)))[…]

The most common command line parameters we observed are still “-NoP -NonI -W Hidden”. Although the arguments can be written in different ways, most attackers stick to the short version. Regardless of the typing, we see that they appear in about three out of four command lines. The ExecutionPolicy flag is not used that often, as it is not needed when only one command is executed by the script.