Improving Visibility and Preventing a Miss: Mandatory PowerShell Logging

One of the greatest risks for a SIEM or SOAR platform is missing that one event that helps with accurate detection.

In general, misses can occur for several reasons, although in our experience, misses mostly stem from incorrect/empty logs or merely a lack of logging required for advanced detection.

Many of us worry that, even though we have everything in place, we are still missing those key events (and yes, we acknowledge that we should never rely on any single event). No SIEM/SOAR platform is a "set it and forget it" tool, so the platforms generating logs should be reviewed frequently to ensure valid logging is in place. Just like we can use GPO to craft good, formal audit logging or use robust audit functionality in Linux, we can take this a step further and force logging in PowerShell.

When any account initiates PowerShell, there may or may not be a measure of logging occurring. However, there is also the potential for accounts to turn off logging, which goes back to our fear of missing something. The most disturbing element of PowerShell is that it can be used to do just about anything without the need to run other programs. This means that in the hands of an attacker, it provides an incredibly powerful ability to own, control, and manipulate a system without installing malware or doing anything else noticeable. Thus, unless you monitor inside of PowerShell, you are likely to miss what's happening.

In this blog, we review how to use GPO to force PowerShell to log, regardless of user input.

This allows PowerShell to detect those key events and to audit any commands issued. Below are simple step-by-step instructions for domain administrators to push out a policy that forces any system in the domain to log all PowerShell activity. This can then be logged via Audit Policy. After describing the Domain/GPO steps, we detail how to force-enable this program on your local machines, including how to enable transcription. 

When there is no evidence of action, there is a high likelihood of missing or failing to detect that event that would trigger an investigation. However, we can easily crank up the bare measures into fully recorded histories of how PowerShell was invoked, by which account, and what commands were issued, regardless of the command result.

If you have any questions about these instructions, please reach out to Castra so that we can help walk you through these concepts, as well as ensure the logs are in your platform of choice.

DOMAIN/GPO Steps

Run ‘gpedit.msc’ and navigate to Computer Configuration – Administrative Templates – Windows Components – Windows PowerShell:

Screen Shot 2020-02-12 at 4.19.27 PM

We are focusing on these two items at a minimum:

Screen Shot 2020-02-12 at 4.20.40 PM

It is important to note that you MUST enter something here. For efficacy, I chose an asterisk (*), essentially saying all modules. However, in the local version, we explicitly forced this using a few specified values. One reason behind choosing an asterisk is that some future applications might use PowerShell in a way we don’t expect, or a new module may be added. For this reason, we chose “anything” for safety’s sake. This is also key for PCI and HIPAA auditing.

Screen Shot 2020-02-12 at 4.22.57 PM

The point is, you can log everything or just some things, depending on your goals. If you are curious about all the modules available to log, run this from an elevated PS shell window: ‘Get-Module -ListAvailable | Select Name’.

Here are just some options that were chosen:

Screen Shot 2020-02-12 at 4.23.36 PM

Note that in GPO, you edit this in a policy that is deployed to all systems, not just domain controllers or some platforms.

Screen Shot 2020-02-12 at 4.23.19 PM

Local / NON-GPO Steps

We still use gpedit.msc. Just note that it pulls up a local version for you to force this change to your system. 

Navigate to Computer Configuration – Administrative Templates – Windows Components – Windows PowerShell:

Screen Shot 2020-02-12 at 4.23.28 PM

I am using custom options of some interest to me. Remember, however, that an asterisk (*) is a smarter choice.

Screen Shot 2020-02-12 at 4.23.36 PM

Screen Shot 2020-02-12 at 4.23.47 PM

And, of course, you have to test it to determine if you have logs.

Screen Shot 2020-02-12 at 4.23.57 PM

I am going to take it a step further and actually log ANYTHING written in any PS shell. Remember to subscribe or pull these logs as they will not be in your normal PowerShell Event Channel. 

Screen Shot 2020-02-12 at 4.24.08 PM

And we can test it with simple commands like “get net-address.” The results are amazing!

Screen Shot 2020-02-12 at 4.24.20 PM

When you are collecting your logs, PowerShell is an event channel you can easily define in your collection tool of choice, and it will likely be parsed in a similar fashion to system and security logs.

Transcription logs aren’t really meant to go to the SIEM, as they are not likely to be readily parsed and reside in a non-standard location and format from regular Windows Event Channel logs. This doesn’t mean, however, that I don’t want to collect them! Using a SOAR platform, I might have after-detection responses that include reaching down for all recent transcription logs or even using a frequent task scheduler that moves them to an off-system location for storage and audit review. Regardless of which path you choose, we do recommend retrieving and storing transcription logs. At some point in the future, we will share our results around collecting these with Wazuh or Elastic and how we retrieve them for forensics with Exabeam or Alienvault.

And there you have it.

Please feel free to contact us with any questions, concerns, or corrections.