John Ferrell 02.9.2021

Malware Deep Dive: Examining A PowerShell Payload

We’re seeing more and more malware that is “Living off the Land,” turning a system's own native tools against itself. In other words, it uses the features and tools that are built into the operating system, such as Windows PowerShell, to perform a malicious activity and avoid detection. 

In this post, we’ll examine a malicious payload that was executed using PowerShell. We found this on one of our partners’ hosts starting from a Run Key value. Let’s dive in.

Snapshot of PowerShell Payload

An HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run value named ਀਀. Well that’s odd. 

The command (value data) is also strange. PowerShell is reading another registry value with the same value name under HKLM\Software.

We can also see that the data the PowerShell command reads from the HKLM\Software\਀਀ value is a base64 string. And not only does it look like base64 but the PowerShell command confirms it by using FromBase64String().

Decoding the Payload

Here's what the base64 string looks like:


Now we'll use Python to decode the the base64 data.

>>> import base64
>>> base64.b64decode(data)
b'$\x00s\x00=\x00N\x00e\x00w\x00-\x00O\x00b\x00j\x00e\x00c\x00t\x00 \x00I\x00O\x00.\x00M\x00e\x00m\x00o\x00r\x00y\x00S\x00t\x00r\x00e\x00a\x00m\x00(\x00,\x00[\x00C\x00o\x00n\x00v\x00e\x00r\x00t\x00]\x00:\x00:\x00F\x00r\x00o\x00m\x00B\x00a\x00s\x00e\x006\x004\x00S[SNIP]

The decoded data above looks like a UTF-16 string (just look at all the \x00 bytes). And just below, Python was able to turn this into something we can easily read.

>>> base64.b64decode(data).decode('utf-16')
'$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("H4sIAAAAAAAAAL1Xe2/iuBb/u3yKa[SNIP]"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();'

Now we have more PowerShell code and another base64 encoded string. This string would appear to be Gzipped as well, note the [IO.Compression.CompressionMode]::Decompress. We can take a peek by base64 decoding it and using Gzip to decompress it.

Here is the full script that was Gzipped and base64 encoded:

In the decoded script above, we can see another base64 encoded string (line 37), and two calls to func_get_proc_address, one for VirtualAlloc() (line 41) and another for CreateThread() (line 55). Malware often uses these functions, first allocating memory for shellcode then executing it with CreateThread().

If we base64 decode the new string, we can see that it contains what appears to be a UserAgent string. This shellcode likely makes an HTTP connection.

>>> base64.b64decode("/OiJAAAAYInlMdJki1Iw...")
b'\xfc\xe8\x89\x00\x00[SNIP]\x00\x00Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; ASU2JS)\x00XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00Y1\xffWWWWQh:Vy\xa7\xff\xd5[SNIP]'

We can use shellen to disassemble the shellcode, but first we need to turn the base64 decoded bytes into a hex string.

>>> base64.b64decode("/OiJAAAAYInlMdJki1Iw...").hex()

Now that we have the shellcode as a hex string, we can paste it into shellen’s disassembly prompt to see the assembly code.

About half way down, there are several instructions that stand out.

The last five instructions load WinInet, the Windows Internet API for accessing internet resources. Metasploit nicely documented shellcode that uses the same instructions to load WinInet.

Now we've found our downloader. 

• • •

We really dove under the hood here to further understand how this malicious code functioned and how the payload worked. We can see how attackers use these “living off the land” techniques to reduce their chances of being detected—and learning from their offensive techniques is the best way to have a stronger defense.

Curious what’s lurking in your networks?

Hackers are constantly evolving, exploiting new vulnerabilities and dwelling in SMB environments—until they meet Huntress. 

We offer a 21-day trial of Huntress for an unlimited number of endpoints. Simply deploy our agent, set up a reporting integration into your ticketing system, and we’ll deliver step-by-step remediation procedures for each compromised host we discover. When the trial ends, our team can remotely uninstall our agents with a single click (no extra cleanup).


John Ferrell

Vice President of ThreatOps at Huntress