WannaMine dropper – Powershell Obfuscation

File details

NAME: file.ps1
TYPE: ASCII text, with very long lines, with no line terminators
SIZE: 3687344 B
MD5: F79F028888C1EED2806179FD256FB239
SHA1: ECCE0CD4C9DD44A1C85E167B7A22EB52B3BD2C70
SHA256: 3F287E29BCB10B200439626D97DD49521816C8DC847797F5ACC7EBFE25B4EFC4
SSDEEP: 49152:60yNRIKiJV1CB3HfqE8HqSi8Hsg91iQCT:q
SIGNATURE: Unsigned

I got bored

Sometime not long before November 2017 I obtained this sample. I have already analyzed it and used it to build WMILister and have evolved WMILister since then. But I wanted to do a write up on the obfuscation techniques I found in it. So this write up will simply cover how I de-obfuscate the dropper. If you decide to analyze a copy of this sample, or similar sample, you do so at your own risk. This particular dropper can place a worm which can spread across a network. This worm is commonly referred to as WannaMine, which is a reference to WannaCry. WannaMine is a crypto-jacking worm but uses the same EternalBlue exploit which WannaCry used. Although, WannaMine uses a powershell variant of EternalBlue. But let’s skip ahead to the de-obfuscation.

So it begins

Firstly, in these screenshots, I have already started to separate the code into separate lines. Originally there were 3 lines (one line was blank). But here is a screen of what I have broken the lines down into:

Line 1 – Is a variable that is 3,683,729 characters long. Currently, this line is boring. It gets used in a Powershell script that gets built later.

Line 2 – Is zero characters long (yes that’s right, I took the time to state that something is zero characters long).

Line 3 – This line is 48,411 characters long. This starts with an open parenthesis and this is not closed until Line 5. The string in this line is our first obfuscated portion that will build a powershell script that will use the $fa variable. More on this later

Line 4 – The main logic to de-obfuscate the string on Line 3 is here. We can see that this will split the on several different characters, then convert item from the split to a character. We also can notice a lot of odd casing of characters. There are capital letters randomly sprinkled through this line. This is a tactic that is attempting to avoid detection methods that are too dumb to ignore case sensitivity.

Line 5 – Simply joins all the separated de-obfuscated strings into one intelligent string.

Line 6 – This is the that makes me scream “STRANGER DANGER!!!!!!!!!!”. If you want to know why, you can simply run this command in powershell to see why (What? You thought you would be able to copy paste it? Nope):

As you can see, it’s a tricky way of using Invoke-Expression in powershell. If you look back at Line 6, you can see that the output of Lines 3 through 5 are being piped into IEX in order to execute it.

Before I forget, Line 7 is an empty line (you’re welcome).

Time for wizardry

But how can we safely de-obfuscate? What ever shall we do? Here is what we do, we fix line 6 to not execute anything but instead, log what gets decoded to another file. DO THIS IN A SANDBOXED ENVIRONMENT!!!!!!! Just like so:

As you can see, I altered Line 6. Also, you have remove the line breaks I added to make this script easier to digest. Otherwise the script will freak out about Line 3, Char 48,411 and I simply don’t have time to worry about that. In short, we replaced the pipe output into IEX to pipe the output into an Out-File. We used NoClobber simply because it sounds cool. But it wasn’t needed at all.

What is in the OutputOfFile.ps1.txt file, you ask? More mess and more stuff to clean up:

Line 1 – Since this starts with an ampersand (damn monkey…if you don’t get that reference, not my problem) the we can tell that the original file with the $fa variable is what is implied to exist here. In fact in lines 2 through 6 we can see “fa” being referenced, but the “$” is obfuscated currently as “sjG” (more on this later). Also, guess what? “STRANGER DANGER!!!!!”. That’s right, Line 1 has another hidden IEX. We can use “Write-Host” to decode that one part as so:

Line 2 through Line 284 is one big ass string (actually the big ass string starts on line one, but I’m just going to say Line 2). But its an organized big ass string. Good indentation, but the text isn’t readable. Well, I guess if I cross my eyes and take 6 shots, it is readable (don’t drink and analyze malicious files…just don’t). But we can see that the very last line is doing a bunch of “.Replace” methods on the string. So lets copy this entire line 284 into a new file and start making it friendlier to read and lets kill that very first quote character of line 284:

Phew….So I have this now to a point where I can easily see there are multiple interesting replacements happening. To make it more human readable, replace “.REPLaCE” with “Write-Host” and run them one at a time in powershell. Also, kill the last closing parenthesis on line 8:

As you can see, I forgot to put “Write-Host” on a few of the commands. I made a mistake. Good thing I was using a SandBox. Although, this mistake didn’t allow anything to become active. So it was a safe mistake that didn’t make me cry. Instead, this mistake taught me something. It taught me that I should be more careful. This time I was safe. Next time, who knows. But you can see what strings will be replaced with other strings. The most significate part of these replacements is that 3 characters will be replaced by 1 character. And we can see that “sjG” will translate to “$” which will then cause lines 2 through 6 to have the fabled “$fa” variable from Line 1 of our original file.ps1.

So far we know that Line 1 has the hidden IEX and that Line 284 has fun string replacement. But how can we get this to be decoded?

Wizardry skill take 2

Here is the secret sauce to this step. You ready for it? Here it is:

Ok, so altering Line 1 to be a Write-Host instead of a hidden IEX isn’t the only step. When I ran this .ps1 file from powershell, I pipped the output of the .ps1 file to out-file like so “Example.ps1 | Out-File -File

Path .\OutputOfSecondFile.ps1.txt -NoClobber” Yup, I used -NoClobber again, simply because I like the way it sounds.

Just about done

So what does the fully de-obfuscated code look like? It looks like this:

As you can see, there is still a little bit of obfuscation by use of concatenation and use of the backtick character. I will simply clean this up by doing a find and replace to remove the ‘+’ and the ‘. I will also add the original $fa declaration back to this script and you will now have an easy to read script like so:

A short explanation of what is in this final screen shot is…

$fa is 5 separate base64 encoded files in one (ps1, exe files, and shell code). Each file will get embedded into the WMI Database. An additional .ps1 file will be downloaded and executed (its just an updated script of what we analyzed and likely isn’t even still hosting anything anymore. I don’t feel like testing it right now.). There is more that this script will do, but it simply is adding persistence using WMI Event Consumers and hiding exe files, ps1 files and shell code into the WMI. Then this infection will worm its way across your network using EternalBlue or credentials stolen via mimikatz (yup, that’s one of the EXEs).

Was your network brute forced via RDP?

This post will detail what can occur if your network is compromised by a Brute Force attack targeting RDP. It also quickly shows ways of determining if you have been a victim of a Brute Force and recommends some extra steps you can take to prevent being a target of an attack of this type. Screenshots used are from a test environment where I simulated a brute force attack but look identical to what I see in the real world with these attacks.

I have assisted multiple different clients who have had their server’s data files encrypted by file encrypting ransomware. The one question they always ask is, “Why did my antivirus not catch this?” Typically, I will find that the installed antivirus has basically been crippled by disabled settings or by exclusions of the entire system drive. But there is one scenario which stands out. After identifying what antivirus is installed, I will attempt to go open the GUI interface for that AV. This is when I find that the antivirus is not installed. When checking event viewer logs, I can find that the antivirus was uninstalled on the same day which all data files were maliciously encrypted. Further proof that their antivirus was installed at one point can typically be found in %ProgramData%. It’s in this folder where antivirus logs and quarantine are typically stored. This is where we begin to investigate exactly what happened to their server.

Although I have dealt with this scenario multiple times. I am going to list the process I take when a client has had some kind of malicious attack on their server.

  • Find out what antivirus they are using.
  • Check what the installed antivirus has recently flagged.
  • If no antivirus is present, verify if it was ever installed by checking:
    • Event Viewer (eventvwr.msc) Application log and filter for about 3 days before and after issue occurred and Event Source “MsiInstaller”
    • Check %ProgramData% to see if any folders for an antivirus exist
    • Check if HKLM\Software, HKLM\Wow6432Node registry keys contain any antivirus registry keys (also check HKCU paths as well)
  • Perform a quick port scan of the public IP Address of the server using nmap and look for any ports which might not be needed to be opened to the outside world:
    • nmap -F <IPAddress>

For the issue of the server having its data files encrypted and files besides those hosted on network shares are encrypted, I always see port 3389 open to the world. Once I see this, I head back to Event Viewer and start filtering the Security log. You will want to filter for the following EVENT IDs

  • 4624 (successful logins)
  • 4625 (failed logins)
  • 4776 (successful credential validation)

It’s also a good idea to filter for the day reported as when the issue occurred or to filter 2 to 3 days before and after the day the issue occurred. Sometimes you might want to start by filtering by just the failed logins, ID 4625. This can easily show you if you had an extreme number of failed logins on a specific date. It’s not uncommon for a brute force attack to last multiple days, all depending on how the attack was planned. Here is an example of a filtered log from a simulated brute force attack:

The key giveaway is that there are multiple failed logins in a very short period of time. In the example, there are tons of failed logins all with the same timestamp. Next, we have a successful Credential Validation. All this tells us is that the brute forcing method was simply trying to validate credentials without fully logging in. Some brute force attacks will not use Credential Validation and simply try to log in repeatedly. Also from the screen shot above, if we could scroll up in the log, you would see that the failed logins stopped. That means either the brute force attack ended and the attack failed, or one of your passwords is now compromised. The simplest way to see if it succeeded or not is to check some of the last few failed logins properties and see which “Account Name” was being used when the attack ended. Once you identify the Account Name, you can then check the successful logins properties to match up the username and then find the successful login with an IP Address.

From the above failed login, you can find the Username which was used and the and the name of the computer which did the attacking. Since I recreated the brute force attack in a test environment, you can see that the name of the computer was “kali” for Kali Linux. In a real-world scenario, this name could be anything. Even something mocking like “pwnage” or something which seems potentially believable to some “cisosecured” or “passwordcheck”. But now that we have the likely used username, we can check the next few successful logins and eventually find the public IP Address which did the attacking. I have changed this IP Address to a fake random IP Address. I have also blurred out any identifiable information about my test environment. I would then next take the IP Address and uses an IP geo-location website to find the relative location of the machine. I then supply this info to the client to investigate if this is one of his User’s IPs or if it is an unknown IP address.

I also discuss with the client the username which was likely brute forced and how the password needs to be changed. I also explain what has happened. The explanation of what occurred to them is as follows:

  1. An administrative account was brute forced via RDP (aka Terminal Services) and a malicious entity logged in to their server with this administrative account.
  2. The installed antivirus was uninstalled.
  3. A malicious file encrypting piece of malware was then used to encrypt all data files on the server and sometimes to encrypt files on any machines located on the network using the C$ of each machine to encrypt.

My recommendations for clients are to force a mandatory password reset to all accounts. Audit and disable any unused accounts (especially administrative accounts). To restore from backups (if these weren’t deleted in the breach) then to put in place a password lockout system and ensure password complexity is enforced. I also recommend to restrict RDP access via IP Address (https://support.managed.com/kb/a2499/restrict-rdp-access-by-ip-address.aspx ) and to change the default port for RDP away from 3389 (https://support.microsoft.com/en-us/help/306759/how-to-change-the-listening-port-for-remote-desktop ). Here are the advantages you get from applying these:

  • Password lockout after failed consecutive attempts – This can stop a brute force attack from every getting close to guessing your passwords for accounts. It can even lead to a user contacting you multiple times a day about being locked out, which can be a clue that a brute force attack is occurring.
  • Enforcing password complexity – Passwords should be more than 10 characters long and should be made up of uppercase, lowercase, numbers, and symbols. Dictionary words should be avoided. Use phrases instead. Users and Administrators should be forced to change passwords periodically every 60 to 90 days. Doing this can help prevent a password on your network from ever existing in a premade password list which are commonly used in brute force attacks.
  • Restricting IP Addresses for RDP – Gives you control of where people can connect from. Yes, you will have to add allowed IP Addresses from time to time, but this is better than finding out all of your data files have been maliciously encrypted and random security software uninstalled.
  • Changing the default port for RDP – A lot of scripted attacks blindly search thousands of public IP addresses specifically looking for common ports to attack. Changing away from port 3389 can cause the scripted attacks to not notice you, thus greatly lessening the odds of becoming a victim of a brute force attack.