Presented at the 2018 SANS DFIR Summit by Mari DeGrazia, Senior Director, Kroll Cyber Risk. Mari's presentation was picked as the 2nd most popular talk across all SANS conferences in 2018.
Malicious PowerShell scripts are becoming the tool of choice for attackers. Although sometimes referred to as "fileless malware", they can leave behind forensic artifacts for examiners to find. In this presentation, learn how to locate and identify activity of these malicious PowerShell scripts. Once located, these PowerShell scripts may contain several layers of obfuscation that need to be decoded.
Mari walks through how to decode them, as well as how to perform some light malware analysis on any embedded shellcode. She also demonstrates how to use an open source python script to automate the process once you have discovered the MO of the attacker in your case.
My name is Mari DeGrazia. I'm with Kroll Cyber Security. And at Kroll, we come across a lot of malicious PowerShell scripts in our investigations. Today, I'm going to walk through how you find these malicious PowerShell scripts and then show you how you can decode them.
But first, one of the themes you may have noticed here at this conference is DFIR Superheroes. You're here to learn how to channel these powers. And so today, I have some prizes to help you channel that inner DFIR Superhero. Some of you that know me know that I'm a maker and I enjoy making things. So right here, I have an Iron Man Arc Reactor. It's going to do a couple of different things. I made it with an Arduino, 3D printed case and I have some Easter eggs hidden in my presentation.
If you see one of these Easter eggs, either raise your hand or stand up. It's a pretty big room. I have my colleagues Ron and Kirtan in here. They'll come around and find you and give you a ticket. Come and see me afterwards and I will give you one of these prizes.
The next thing I have is the Lasso of Truth here from Wonder Woman, right? Nice strong, powerful woman, so we got to get this going. Rob, if I can have you come up here to help me test this Lasso of Truth, I would greatly appreciate that.
All right, so go ahead, hold one end and I'll wrap it around you. Yes, here we go. Okay, so, Rob, I know you can't see this but it lights up. Can you tell me the last time you were in Vegas at the Cosmopolitan, how much did you really lose on the Blackjack tables?
Wait a minute, we got to demonstrate if this works.
A lot, okay? We won't disclose it here. We're all professionals, okay.
On account of the drinking, more than I usually lose.
Close enough, close enough. Thank you. So, keep your eyes open for these Easter eggs. See if you can find them and if you want one, make sure that you stand up or raise your hands so that you can be seen.
Why PowerShell? We've had a couple of presentations already that have demonstrated how powerful PowerShell is. Yesterday, Devon Ackerman talked about Office 365 and how he leveraged PowerShell to access Office 365. We had another presentation today where they were demonstrating techniques of stealing tokens with PowerShell. This is a very powerful language just like the name, PowerShell, would suggest.
This lets attackers live off the land. They don't have to bring a binary with them and drop it on a system. They can leverage the tools that are in Windows systems to actually get what they need done. This also helps them be file-less. Like I said, they're not dropping a binary on the system. They're getting to use the tools that are on Windows natively; this ultimately helps them evade anti-virus (AV).
They're in there. They're getting things done. The last thing they want to do is start tripping that AV to let us know that they're in there. They also want their tools to run. If AV trips and starts catching those tools, of course, they're not going to be able to do what they need todo. PowerShell gives them full access to WMI and the .NET framework. These are both powerful tools.
If you think about these tools, these are things that administrators use to do their job. Whatever can be used for good can also be used for evil. Also, there's a huge lack of logging when it comes to Windows PowerShell. When we talk about logs as forensic examiners, before Windows 10, there wasn’t a lot of logging for PowerShell by default.
Now, you can go on, take some additional steps on some older systems, update some libraries, get that PowerShell logging installed but even after you get that PowerShell logging, there's additional steps you have to take to enable it. In a lot of the cases that we work on at Kroll, we don't see this. We get into an environment and very rarely do we get adequate logging associated with PowerShell.
What kind of bad stuff can you do with PowerShell? You might not have your attacker taking off with a whole stadium like Magneto did but it definitely does some damage. You saw those demonstrations earlier with PowerShell. You can do a ton. You've got the data exfiltration. You've got the recon. You've got the remote command execution. Pretty much anything your attacker wants to do, they can leverage PowerShell to do this and a lot of it, like I said, is done in memory.
Here's an example; something that I have seen a lot within our investigations. One way that they use to push out PowerShell within the environment is the service control manager and I kind of like to call this spray and play because if you find this on one system, there's a good chance you're going to find it across your entire environment on a lot of systems.
The service control manager is a native tool built into Windows. It allows you to install services and to manage them, stop them and start them. So, it's pretty simple. You just use the command “sc”. Another good way to think of it is like a poor man's PsExec. The service control manager; you can execute on remote machines.
You think about using a tool like PsExec, well the attackers are already leaving a footprint. That's not a native tool to Windows. That's the PsExec tool. They bring in a tool, PsExec, to push things out remotely but the service control manager is a native tool built into Windows that they can use.
If you're familiar with some of the artifacts left behind by PsExec, if you use it, it makes an entry in the registry key when you accept the EULA. Well, not with the service control manager. So here, they have a tool that lets them access any Windows system in the environment remotely.
They're going to use this and they're going to call the create command and then supply a service name. Now, here I've used the “FakeDriver” service name but typically what we see in our investigations is a random service name, which could be anywhere from 12 to 16 digits with capital and lowercase letters. They do this because the service control manager wants a unique name.
If they're pushing it out to multiple systems, multiple times across the environment, they want to make sure that there's no collision in the service control name. They'll use a random name here. The next thing they supply is what's called the binPath, the binary path. So normally, if you're installing a legitimate service in Windows, this would be where you would supply the path to the executable that you're going to run. But here, what they do, instead of pointing it to a legitimate service, is they point it to cmd.exe; and then they're going to leverage cmd.exe to run whatever PowerShell command it is that they want to run.
And don't forget, they can do this remotely on any system. And here, we have some other variables that they'll use. They'll use the -c, -q, so that when that command prompt and PowerShell pop up, it's quiet, right? Because if they're on a system, the last thing they want to do is to alert you that they're there.
Right here we can see they're basically setting up a reverse shell to Meterpreter. Meterpreter is very strong, very powerful. So, ultimately their goal is to have a reverse shell set up into Meterpreter. And like I said, you're going to see this across multiple systems within the environment. Here's what that attacker actually sees at his/her end. They set up a listener and they're going to listen for that. So once they execute that command, it's going to establish a reverse shell up to their system and boom, now they have access to that from their system that they're working off of.
If all of this is done through the command line, filelessy so to say. They're not downloading a backdoor that's executable. How do we as examiners find evidence of this? Well, the service control manager is actually logged in the system event log. Right here is your magic number that you're going to want to look for: 7045. This is the event log ID associated with new services installed on a system. When they run that “sc” command, it will leave an entry in the system event log.
What does it look like? I ran through an example that was in plain ASCII but normally, the attackers are going to use obfuscation. Now, it's my understanding through some exercises yesterday, you saw some base64 and you're going to see the same thing here. Here we have an event ID 7045 and right here you can see, this is what the random service name is going to look like. And then right here is where you see the COMSPEC, which is that cmd.exe on the system and they're calling PowerShell. And like I said, this is base64 encoding that you're going to see when you start looking at these entries.
Now, when it comes to base64, as a programmer, base64 can actually look a couple of different ways. And I have two different ways right here. Can anybody tell me the difference between the base64 on the top? And I think I saw a hand over here. Jake, was that you? I think this was the first one I saw. Where did you see the Easter egg?
Princess Diana right down here. So, Jake has got the first prize. They'll come over and give you the ticket. So, the base64 on top is Unicode-encoded. You can see there's a lot of As in here. It just looks different than the base64 down here. You can also see there are some slashes and some different varieties.
When you're looking at base64, you kind of start to recognize these patterns, Unicode and regular. Programmatically, I like to deal with things in Python. I know this is about PowerShell but if you go to my GitHub and you look at the things that I've worked on, I like to do things in Python. I'm stubborn. I should probably learn PowerShell but I'm going to root for this because I want to learn how to do this in Python.
A lot of my current scripts are in Python, my processes are in Python, so I just kind of want to roll with this decoding in Python. Python, if you've never used it before, it's simple, easy to use. Just type Python, it's going to drop you down into an interactive shell to run some commands. We're going to just run the “import base64” so that we can decode this base64. Supply a variable “code” that we're just going to drop that base64 into and then finally just do base64.b64decode(code)and we get the code.
What does this look like on that event log that I supplied earlier? Same thing. Now, the event log that I had earlier was actually Unicode; so this is where we have to specify UTF16. That's actually going to decode our Unicode base64. And this is what it looks like.
And then right here, this is what I'm looking for. This is the golden egg for me. This is the IP address that those attackers are using to establish that reverse shell. Now, sometimes, it's going to be an external IP address. Sometimes, it will be an internal IP address. We just worked a case and it's pretty common in these PFI (PCI Forensic Investigations) investigations where they're stealing credit card data like my colleagues Ron and Brandon talked about yesterday.
They'll find one system or maybe two systems within the environment that have connectivity to the outside world. So, they'll attack the point of sale systems through the backup house and then they'll set up one of these reverse shells to an internal system and then go out from there. When you're looking for these IOCs, you're going to see both internal and external IP addresses embedded within this code. I wish it were that easy, right, because then my presentation would be wrapped up. We'd all be going to lunch, but there's more. Very rarely are you going to get just one layer of base64. It becomes like a Russian stacking doll. They're going to use multiple upon multiple layers of obfuscation to hide what they're doing and to make our jobs as investigators more challenging and difficult.
Here's another example, 7045 with COMSPEC. Now, you guys should start to notice a theme here with the COMSPEC. They're calling PowerShell.exe. But this one, this one is using compression, GZIP compression. So, the first time I saw this, I was trying to figure out, "Okay, I see the base64. I see there is some kind of compression; I need to figure out how to decode this."
What the attackers have done in this situation is there's a payload. And then that payload is compressed and then there’s base64. In order to decode that, we've got to reverse the process. We have to decode that base64. We have to decompress it and then finally, we get our payload. I already talked about how to decode the base64 but this time instead of writing out to the screen, we're going to drop it into a file.
Now, programmatically, if you're familiar with Python, you don't necessarily have to drop it out to file but the first time I did this, I wanted to see if these steps work so I kind of wanted to break it down to the basics. Once I went ahead and dropped that into a ZIP file. I think I saw right here, what do you see? Stark, right here. All right, Iron Man's real name, right, Stark. The first time I did this, I went ahead and I decoded that base64 and put it out to a GZIP file and then I used 7zip to unzip it and I about fell out of the chair when it actually worked because I was like, "It couldn't be that easy, right?" And so, this is what I got though. I looked at this and I was like, "Where's my IP address? Where's the code?" I know that I took the right steps because I didn't get an error when I tried to decompress it but it wasn't a ZIP file. Python would have thrown out an error to me or it just wouldn't have looked like anything.
This is actually shellcode. Within the base64, within the compression, there's now shellcode. I am not a malware reverse engineer. My home is the host-based forensics but there are things that I can do to kind of get the low-hanging fruit to see if I can find those IP addresses; so that I can pass them off to my clients quickly so that they can start blocking IP addresses. And like I said, there can be internal IP addresses so I want to look for those so I know what other systems I can start looking at.
There's this great utility I like to use by PDFstreamdumper called scdbg.exe and this is just a nice simple program that you can run over the file quickly to see if they can pull out any interesting information from the shellcodes. It's pretty simple to run, scdebug. You just point it to the file and it will run over that shellcode. And boom, right here I can see some libraries are being called, a WSAsocket. And then boom, I get my IP address.
Now, I don't have all the other code that goes along with this, but I know based on this event ID, I know based on this methodology and based on what we're seeing out there that this is more than likely that reverse Meterpreter shell that I'm looking for.
Okay, but wait, there's more. We had the base64, we had the compression, we had the payload but the attackers are still doing more to obfuscate this data. Here we've got a random service name, we've got the COMSPEC. Now, can anybody tell me what type of base64? Is this the Unicode or is this the regular base64? This is the Unicode, right? This is what it looks like. You can tell it's a lot more voluminous. It has the A's in it. You don't see any of the slashes in it, so this has been Unicode.
And so we know about the Unicode and here you can see there's an encoded command. And one thing about PowerShell is sometimes you won't actually see the encoded command. They'll use the shorthand for it that I think is -e. Here, they have a -nop which means no profile. They're going to run the PowerShell with no profile but sometimes you'll see the -nop written out as no profile.
So, like in the presentation previously where they were talking about all the different variables and how you can switch it up with this PowerShell signatures if we start thinking about those signatures, same type of thing. It might be spelled out encoded command. It might be -e. It might be spelled out no profile or -nop or -w hidden or whatever the shortcut for that is. Those are things that if you're running your keyword searches, you're going to have to be careful about that you don't get trapped into just thinking that only one type of command is always used.
Right here, we decoded that first layer of base64 and guess what we get again? We get another layer of base64, so they base64-encoded it to Unicode. Now we have regular base64 again. And then on top of it, we get compression. But this time, if you scan the string, you're going to see it's not GZIP compressed. It just says IO compression.
And like I said, I am not a PowerShell person. I'm a “Pythonista”. I love Python. And so, I wanted to figure out, okay, what kind of compression is this? It's not GZIP. I tried running it, putting it out to GZIP file. So, silly me, I think, "Okay, this is Windows, right? This has just got to be regular compression." So, I just put it into a regular ZIP file. I tried to open that up, it doesn't work. I tried several different Python libraries to decompress this. I tried seeing if it was a TAR file, a RAR file. I couldn't figure out and then finally, I figured out that I must call it just like the .NET compression.
I know that people in here who know PowerShell are probably thinking, "Yeah, that's what it is," but I work with Python and if you're familiar with Python, Python is cross-platform compatible. It runs on Windows. It runs on Linux. It runs on Mac. So, when you talk about .NET, Python isn't going to restrict itself to just running on Windows. But me being stubborn, I'm thinking there has to be a way to do this in Python. I want to figure out how to do this in Python, when I found something called IronPython. IronPython brings in the .NET library so that you can utilize Python to do some of the things on Windows.
By leveraging IronPython and some of the libraries, I was able to import those libraries into Python so that I can access what I've just kind of nicknamed IO compression or .NET compression because it seems specifically related to PowerShell, not the typical compression that you run across. Here, I've just imported the libraries. I wrote a function where basically it's going to take that decoded base64 and then it's going to decompress it and give me the text file.
Here's an example of how you run it. You run it just like regular Python, except you call ipy.exe and the name of the script. Here's an example of what an embedded script looks like once again setting up a Meterpreter shell. We have an IP address with a port. Now, in all of these examples I've shown you, the PowerShell code embedded within that base64 can vary. You're not always going to see the same script embedded inside that base64.
The other thing that's frustrating is within a case, what you're going to see or what we have seen are variations. Everything that I just ran through, that's not what you're going to get. These pieces are going to be put together in different ways. Sometimes, it will be base64 encoded. Sometimes, it will base64 Unicode and then you're going to have your compression, your IO compression and your GZIP and then maybe your shellcode. But, you never quite know what order that's going to go into and what you're going to do.
And within each case, it's going to vary. So, maybe on May 5 when the attackers are in, they use one methodology, so great, you come up with your script. You got everything running. You got everything working and then you find a whole new set of log entries from another day and it's going to be completely different. A lot of times, they're using tools to automate this on the backend to push it out. I talked about that example before where they're using SC to push it out within the environment. You're thinking, "Okay, they're using the service control manager. That's persistent.” “No." They're actually just using the service control manager to push it out. If you look in the event logs, you'll see an error because it's not a legitimate service. They're just leveraging it to push it out. So, they still haven't gotten their persistent mechanism yet.
Ultimately attackers want to survive that reboot. They want that persistent mechanism within the environment, so there is something that we've come across called WMI persistence. And basically, they're using the subscription service within the Windows management instrumentation to basically ... I'd like to think of it like a scheduled task that is triggered by an action.
Part of the subscription is a filter. So, in the filter, they can set certain triggers that will trigger this backdoor to happen and then once that filter is triggered, it will point to a consumer. The consumer is the executable or the script that will run and I'll show an example of this in a minute.
And then the third part of the subscription is what's called the filter to consumer binding. It's just the part within the WMI that's going to say, "Hey, once this specific action happens, this is the file that I want you to execute." And this is all stored in a file called objects.data in C:\WINDOWS\system32\wbem\repository. There's a great Python script, of course, Python, that you can run over this file that's going to help you find these things, PyWMIPersistenceFinder. I went ahead and ran the script. You can get this on GitHub by David Pany. I ran the script over one of these, and let's take a closer look at this. Here's a filter called updater. I saw a hand ... I couldn't quite see Ron or Kirtan over here. You want to tell us what you see? Jarvis, right here. Here we have a filter called updater and it says AND Targetinstance.EventCode = '4625' And Targetsinance.Message Like '%admin%'.
What do we think? What's the event code 4625? 4625 is associated with a failed login and then admin. This means that if we have a failed login for an admin account, go ahead and run the consumer which is going to be our PowerShell script. Basically, all the attacker has to do to get their batch shell to trigger is go in through rdp and try and add in, log in like an admin and even if that password fails, if they change that admin password in the environment, it doesn't even matter. The attacker just goes in and tries any password and as long as it fails, it's going to trigger that persistent mechanism.
And once again, that persistent mechanism is base64. Here's the name of it. It's called updater and here's our tie in right here that ties the filter to the consumer name and then, of course, our base64 encoding. Now, like I said, this can be encoded in all those different layers and all those different levels, so you'll have to go through and decode that.
Now, when we talk about persistent mechanisms, the registry. The registry has lots of good places for persistent mechanisms. We've got the autorun keys. We have installed services. So, using the tool registry explorer by Eric Zimmerman, you can go in and start looking for these things.
Here is an example of an autorun key. And typically, what I've seen is I kind of call it following the breadcrumbs. If we take a look at this autorun key, we can see the COMSPEC. We know that COMSPEC is cmd.exe.exe. And typically, you're not going to see that be referenced like this in the registry. And then we can also see from base64. But if you look here, there's no base64 here. Where's the base64? We can see there's something bad going on but there's no base64 here.
And what this code does is it references another key. Right here, it's saying go get this key and then run whatever is in this key. Then, you have to go find that key to actually find the base64 code. And you can see right here there is a pretty big chunk of code. Now, if you see something like this, of course, it should be a huge red flag because most programmers are not going to do something like this and put it in the registry.
PowerShell logs, if you are lucky enough to get PowerShell logs in your investigation, can be a great wealth of information. And I believe Matt Bromley and I worked a case where we saw something like this. If you go in and you look at these PowerShell codes or the PowerShell log, you're going to find what's called a script log. The attackers will use a command called download string and that download string will download something off the internet into memory. And then when it's in memory, they can launch it. Something we'll see a lot of is something called invoke shellcode.
And a lot of times, they don't even stage this on their own system or at an IP address that you can pivot off of or see a connection to; it's on GitHub. They literally go and download the code directly from GitHub. And once they do that, they execute it. And in this particular instance, they inject it into a process and this time it was Notepad. Now, sometimes, I mentioned we can kind of use programs like scdbg to go through and get that low-hanging fruit out of the shellcode. But sometimes, you just might not be able to decode the shellcode. But here, we have a process that we know that the shellcode is associated with, with Notepad. If you are lucky enough to get a memory sample along with it, you can go into that memory sample and pull out those IOCs rather than jump through hoops to decode that shellcode.
Were there any hands that went up on the last slide? Anybody see that? Did I see a hand? I'm not sure who was first. I think over here in the red shirt. Did you ... What's that?
Yes. That's Wonder Woman's invisible plane. It's really hard to draw an invisible plane, so that was the best that I could do. She’s invisible but we can see her body right there a little bit. I was wondering about that and what good does it have to have an invisible plane if you can see the person in it.
Anyways, if we get a memory sample, we can run volatility over this memory sample to dump what is in that Notepad process to pull out those IOCs. So, we use the command called image info, on the memory sample to get the profile. Then moving forward, we use that profile. Then we're going to run pslist to get the running process list. We find out which instance is Notepad and then we go ahead and run the malfind which is going to find injected processes and it's going to dump it out to a folder.
And once we have that dumped out, like I said, I just do the real simple stuff, grab the low-hanging fruit. I'm just going to run strings over that and see what I can find. And right here, I've used the inject shellcode; it's injected Notepad. I'm able to dump that process and get the IP address out.
There's not, but did you find something? Is that ... What is that? Tell me. Is that Iron Man or Wonder Woman?
Oh, Aquaman, okay. We're going to hold another ... Seen in another universe. Then these guys, I don't even know. I love him though. He's pretty awesome.
So, in summary, what are the IOCs that we can look for as investigators? I just kind of wanted to present a slide with all our IOCs. System event log 7045. So, if you've got a [inaudible 00:32:57] like we do. I work with Scott, he's able to go through and pull out all these event logs in one shot and give us all the base64 and we can go through and decode it. This is what I like to call a great magic number, which, immediately as you start an investigation, you can start looking for this event ID and see if you've got this activity going on in the environment.
There's also the event code that is in proximity to it, the 7009. This is the failed event. What happens is that service control manager tries to start up. It fails because it's not a legitimate service, so you might also see the 7009 close by.
The other thing is if you get these Windows PowerShell logs, you can look for these things. The download string, executing a remote command; and you can also just sort by the warnings in that event log. And Windows does a good job of identifying those as malicious within the event log itself. Search for that COMSPEC. Now, you’re probably not going to want to run that as a keyword or search the entire computer, but we know that we see it in the registry. We know that we see it in the event logs. So, that's a place that you can be looking for.
And RegRipper is a tool that I love to use because it's a command line tool. I can roll it in with my processes. You can use two plugins in RegRipper to help you find this. The Autoruns is going to show you that first key and then you have the Sizes. The Sizes plugin will look for any values within the binary and the regsize within the registry that are over a certain threshold. And, because we know that PowerShell takes up a big chunk in there, it's going to pull this stuff out for you immediately and it does a good job. I shared my findings with [Harlan 00:34:45] and he updated his plugin to help support that.
All right, big round of applause for Mari.