How long was the malicious PowerShell script active on the compromised machine?

After long break I am here again, and this time I will show you very handy PowerShell logs that will help you understand how long the malicious PowerShell script was active on the infected device.

The logs I am talking about can be found in the log file named Windows PowerShell.evtx. Probably you have seen them before, but I wonder if you parse them in the way I am going to show you. There are two specific IDs that you should make yourself familiar with:

  • Event ID: 400
  • Source: PowerShell
  • Category: Engine Lifecycle
  • Message: Engine state is changed from None to Available.
  • Event ID: 403
  • Source: PowerShell
  • Category: Engine Lifecycle
  • Message: Engine state is changed from Available to Stopped.

More PowerShell logs you can find here, this website lists them in a very nice way.

The first log (event ID 400), can look like that:

As you can see, there are some important information. The first one is the event’s message, saying “Engine state is changed from None to Available“. Simply saying it means that the script was started, but what script? That information can be found by checking a field named “HostApplication“. In that case it is “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command if((Get-ExecutionPolicy ) -ne ‘AllSigned’) { Set-ExecutionPolicy -Scope Process Bypass }; & ‘F:\Test1_Ping.ps1′”. So we know when and what script was started, but when was it completed? To get that information, we have to take a look at the second log (event ID 403), which in turn can look like that:

Now we have the message saying “Engine state is changed from Available to Stopped”. That means the script was completed. But how can we match these logs together? I found out, that we can use a field named “RunspaceId”. In my tests, that filed was always enough to match the script creation and the script termination (I do not know if that ID is unique or not, but I will monitor that performing my investigations). But in addition to that, we can also check script path, to see if it’s the same.

But there is one problem… sometimes event ID 403 is not populated. For example:

Example 1.
If a user manually starts PowerShell.exe and then closes it by clicking on the exit button (top right corner of the window), the event ID 403 is NOT populated. But if he closes the PowerShell console by using a command EXIT, then the event ID 403 is populated.

Example 2.
If the user starts a script and stops it by clicking on the exit button, the event ID 403 is not populated (like in the first example). But with the script executions, it’s more tricky. If it is a GUI script, then you will get two windows. The first one showing a script’s interface, and the second for PowerShell console. Example below:

If you close the GUI window, by pressing the EXIT button, then the event ID 403 is created. But if you close the PowerShell console window, then the event ID 403 is NOT created.

Example 3.
And finally we have PowerShell_ISE.exe. For this process, you always get both events (at least based on my tests).

Of course if you have a script, which takes some actions and then exists (let’s say without the user interaction), then both logs are populated.

Why should we match these events? Because we can, and if we can we do. But if that argument does not convince you, then think about the situation when you have a keylogger running on the system (which was deployed as a PowerShell script). Would you like to know, if the script was active when your admin was logging to the critical resource in your organization? The majority of analysts, would see the execution of the script and assume that it was active. I really do not like that approach, I always do everything what I can to say HOW LONG process was active and how could that impact the investigation.

And now the most important part, how can we match these events? Probably the manual matching would take hours, therefore I automated that process and created a PowerShell script which does it for us. Like always the script can be found on my GitHub page.

I am not going to describe that tool here (because I did it on my GitHub page), but I will show you a small screen illustrating what you can get using it.

In addition to to that, the output is saved to a file as well as two timelines (in TLN format) for both events 400 and 403.

Leave a Reply

Your email address will not be published.