Living off the LAN
When an attacker uses tools native to the operating system it is referred to as Living off the Land. Personally, I think it should be called Living off the LAN because it’s a techy play on the acronym for Local Area Network. This blog post will cover Living off the Land activity associated with Carbanak/FIN7 that Trustwave SpiderLabs encountered during a recent investigation. The post will include:
- Which Windows Event Log IDs associated with malicious PowerShell activity to search for.
- How to search for those IDs with the PowerShell cmdlet “Get-WinEvent”.
- How to analyze malicious PowerShell payloads with PowerShell.
- How to analyze malicious PowerShell payloads with Python.
- How to analyze shellcode that is injected/threaded with PowerShell.
This story begins with Shawn. Shawn’s my boss. Shawn provided me a forensic image and told me to find evil. We had IOCs of the malware that infected the clients PCI environment. I searched for the IOCs on the image and analyzed the events within the suspect compromise window, but I wasn't finding any significant leads. I synced up with Shawn and asked for guidance. One of his pointers was to review the PowerShell activity.
My analysis found two suspicious “Script Block Logging” entries in the “Microsoft-Windows-PowerShell/Operational.evtx” event log file. Script Block Logging entries have an ID of 4104 and are recorded when the Group Policy setting “Turn on PowerShell Script Block Logging” is enabled, or whenever PowerShell deems the script it ran to be suspicious. When any two of the said events are met, Windows PowerShell will log the processing of commands, script blocks, functions, and scripts whether invoked interactively, or through automation. I found the two suspicious Script Block Logging entries using the PowerShell cmdlet “Get-WinEvent”
Get-WinEvent -FilterHashtable @{Path=“Microsoft-Windows-PowerShell%4Operational.evtx ”;id=4104}
|
I highly recommend using the “FilterHashTable” option because it will improve the search performance of the Get-WinEvent cmdlet. Hash tables are very efficient for finding and retrieving data. The first suspicious entry appeared to be a PowerShell payload that was base64 encoded and compressed.
The second entry appeared to a PowerShell based meterpreter payload. This meterpreter payload has been reported to be seen in the wild as a stage two payload of Bateleur. I assumed that the second suspect Script Block Logging entry was the product of the first, but I needed to confirm that assumption. Through my analysis, I found two ways to decode and decompress the payload, one with PowerShell and one with Python.
Analyze malicious PowerShell payloads with PowerShell
To neutralize the suspect payload so that I could run it in PowerShell, I removed all of the execution commands. The execution commands include:
- -NoE (NoExit) – Doesn't exit after running startup commands, creates a process
- -NoP (NoProfile) – Doesn't load the PowerShell profile.
- -NonI (NonInteractive) – Doesn't present an interactive prompt to the user.
- -ExecutionPolicy Bypass – Nothing is blocked and there are no warnings or prompts.
- -C (Command) – Executes the specified commands (with any parameters) as though they were typed at the PowerShell command prompt.
- IEX (Invoke-Expression – Runs commands or expressions on the local computer.
So, we go from this:
powershell.exe -NoE -NoP -NonI -ExecutionPolicy Bypass -C sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(‘MALICIOUSPAYLOAD=='),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd() |
To this:
sal a New-Object;(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(‘MALICIOUSPAYLOAD=='),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd() |
Running the neutralized payload in a Windows 7 virtual machine that was snapshotted and its network adapters disconnected confirmed my assumption. The second Script Block Logging entry was the product of the first.
Analyze Malicious PowerShell zlib Compressed Payloads with Python
I wanted to find another way to decode and decompress suspect PowerShell payloads without having to rely on a Windows virtual machine. To achieve this, I turned to Python. I knew the payload was base64 encoded but I was stumped on the compression. After researching and some trial and error, I found that the compression algorithm used for the PowerShell function “[IO.Compression.CompressionMode]::Decompress” is zlib. There is a catch, the payload is a raw stream and does not include a zlib header or trailing checksum. So, if you attempt to decompress the base64 decoded payload with the ‘zlib.decompress’ function from the Python zlib library or 7zip they won’t recognize the compressed data.
In order for the ‘zlib.decompress’ function to recognize the base64 decoded data as a raw stream of zlib compressed data, you have to set the second parameter, wbits, of the zlib.decompress function to ‘-15’. The wbits parameter controls the size of the history buffer (or “window size”), and what header and trailer format is expected. The -15 value in the wbits parameter indicates that the input is a raw stream with no header or trailer. In conclusion, I came up with the following script:
import base64 import zlib import sys
if len(sys.argv) == 1: print "Usage: " + sys.argv[0] + " {base64 encoded and zlib compressed payload}" else: encoded = sys.argv[1] print sys.argv[1]
decoded = base64.b64decode(encoded) # The -15 value in the wbits parameters indicates that the input is a raw stream with no header or trailer. decompressed = zlib.decompress(decoded, -15)
print decompressed
|
The Python script is easy to use. It only requires one argument which is the suspect PowerShell payload.
At this point in the investigation, I was provided a great amount of Windows Event Logs in Syslog format. One of the attacker's modus operandi was installing services on the Windows systems. These services would spawn a Command Prompt with the %COMSPEC%” environment variable, invoke PowerShell and run a malicious payload. The ComSpec environment variable contains the path to cmd.exe. If you’re ever in a situation where you need to search a lot of ASCII text logs and have a multicore system, I highly recommend using the Linux tool “parallel”. Parallel is a shell tool for executing jobs in parallel using one or more computers. A job can be a single command or a small script that has to be run for each of the lines in the input. The typical input is a list of files, a list of hosts, a list of users, a list of URLs, or a list of tables. Here’s an example of the two tools in use:
$ find /logs/ -type f -print0 | parallel -0 -k 'grep -aFi "comspec" {}’ >> compsec.txt |
The find command creates a list of files which is then piped to parallel. For the parallel command, the “-0” option means that no arguments will be passed to the command and the “-k” command tells parallel to keep the sequence of the output the same as the order of input. Lastly, the command to be parallelized is grep. The “-a” option indicates that all files should be treated as if they are text files. The “-i” tells grep to ignore case distinctions in both the pattern to be matched and the input files, and the “-F” option tells grep to interpret the pattern to be matched, “compsec”, as a fixed string instead of as a regular expression.
The majority of the malicious PowerShell services found using grep were similar, they were base64 encoded and zlib compressed, but the other services found were using the Gzip compression algorithm. Another interesting item about the gzip compressed PowerShell payloads found is that there was a gap between their presence and the zlib compressed payloads. A change in the attacker's modus operandi?
Analyze Malicious PowerShell gzip Compressed Payloads with Python
To analyze these new gzip compressed payloads, I created a Python script similar to the zlib one and used the gzip and io library.
import base64 import gzip import sys import io
if len(sys.argv) == 1: print "Usage: " + sys.argv[0] + " {base64 encoded and gzip compressed payload}" else: encoded = sys.argv[1] print sys.argv[1]
decoded = base64.b64decode(encoded)
f=open("decoded.gzip",'wb') f.write(decoded) f.close
with gzip.open('decoded.gzip','rb') as f: with io.TextIOWrapper(f,encoding='utf-8') as dec: print(dec.read())
|
Again, the Python script is easy to use. It only requires one argument which is the suspect PowerShell payload. The Python script first base64 decodes the payload and saves the results to a file named “decoded.gzip”. The decoded payload is then decompressed with the “gzip.open” function and printed to standard output.
Using this python script against the suspect gzip compressed payloads, presented me with another PowerShell payload! Upon seeing this payload I immediately thought that is more complex and needed to be analyzed properly. I submitted the suspect gzip base64 encoded PowerShell payload to our incredible team of malware reverse engineers for analysis. As I waited for the results, I was curious about the payload and began to analyze it. A cursory review of the second stage PowerShell payload revealed three interesting variables near the end of the script: eN8yc, nLt5S2Irnq8, and t0liCIPztb. eN8yc appeared to be base64 encoded data. nLt5S2Irnq8 appeared to allocate space in memory for the length of eN8yc and copy the contents of eN8yc to the memory allocated. Lastly, t0liCIPztb appeared to create a thread to execute the code allocated by nLt5S2Irnq8. This led me to theorize that eN8yc could potentially be shellcode.
I base64 decoded the contents of the variable "eN8yc" by piping it to the Linux command “base64” with the “-d” option for decode and saved the results to a file named “payload”. Opening up the file named "payload" with a text editor, such as vi, revealed no human-readable text. This was a good sign that it this was machine code, thus likely shellcode.
$ echo "base64encodedshellcode//" | base64 -d > payload |
One way to analyze shellcode is to emulate it. I attempted to emulate the shellcode with sctest from Libemu. Libemu is a library which can be used for x86 emulation and shellcode detection. I passed the decoded shellcode to sctest over "standard input" with the option -vvv for very, very, very verbose, -S to read shellcode from standard in and -s 2000000 to run two million steps.
$ sctest -vvv -S -s 2000000 -G payload.dot < payload |
After running the sctest command I was presented the following.
In the screenshot above we see that the ws2_32 library is loaded. ws2_32.dll is a legitimate library that provides network functionality. This tells me the shellcode has network capability but what else?? I did some researching and found a helpful article by Didier Stevens. It turns out that sctest doesn’t fully emulate WIN32 API functions. A better tool to use for analyzing shellcode is scdbg.exe. scdbg is a shellcode analysis application built around the libemu emulation library. When run it will display to the user all of the Windows API the shellcode attempts to call. Scdbg.exe is included with PDFStreamDumper, so I installed that on a Windows 7 virtual machine. I transferred the base64 decoded shellcode and emulated with scdbg.exe using the following command:
C:\> scdbg.exe /f c:\shellcode |
I was presented with the following. Again, we see that the ws2_32 library is loaded. We then see that a TCP bind port is set on port 1234. Excellent!
By this time, the malware reverse engineers got back to me with their findings and confirmed that the shellcode is a bind shell. I synced up with Shawn and we both agreed something didn’t seem right. The shellcode seemed "pentesty". We created a timeline of all of the malicious PowerShell service installations and presented it to the client. The client confirmed that they had a penetration test and that the systems compromised with the gzip compressed PowerShell payloads were reported in the penetration test report. However, the zlib compressed PowerShell payloads were not reported in the penetration test thus were attributed to the Carbanak/FIN7 group.
In conclusion, attackers are continuing to and improving their use of Living of the Land methods. Malicious PowerShell payloads similar to the aforementioned zlib payload have been seen in the wild as the secondary stage of their attack. The first stage being a Microsoft Office document ridden with malicious macros. If your organization if not using macros, configure your Windows systems to disable all macros without notification. Furthermore, educate your end users on what they can do to detect and defend against malicious Office documents. Be wary of PowerShell activity in your environment. Enable the Group Policy setting “Turn on PowerShell Script Block Logging.” This will ensure that suspect PowerShell activity is logged. Search for Event Logs with an ID of 4104. Feel free to use the Python scripts within this post to analyze base64 encoded zlib or gzip compressed malicious PowerShell payloads. I recommend using scdbg.exe to emulate shellcode. As we saw, sctest doesn’t fully emulate WIN32 API functions. Lastly, use all of your resources and communicate with your team!
ABOUT TRUSTWAVE
Trustwave is a globally recognized cybersecurity leader that reduces cyber risk and fortifies organizations against disruptive and damaging cyber threats. Our comprehensive offensive and defensive cybersecurity portfolio detects what others cannot, responds with greater speed and effectiveness, optimizes client investment, and improves security resilience. Learn more about us.