Monitoring Digitally Signed PowerShell

The Challenge

Microsoft Windows PowerShell is a powerful scripting environment. The PowerShell execution polices are provided in order to let you determine the conditions under which scripts may be run. The default option is “Restricted,” which doesn’t allow any scripts to be run. You can find a summary of the other options in the list below.

Option Description
Unrestricted Unsigned scripts can run
RemoteSigned Requires a digital signature from a trusted publisher on scripts that come from the Internet (including email and instant-messaging programs), but does not require digital signatures on scripts that you have written on the local computer
AllSigned Requires all scripts to be signed by a trusted publisher, including scripts that you write on the local computer
Bypass Nothing is blocked and there are no warning or prompts
Undefined There is no execution policy set in the current scope

See full descriptions here.

The purpose of the Execution Policy is not to stop the user from running unapproved applications. Rather, it is a way to prevent an attacker from running scripts that the user hasn’t approved.

This is an important distinction, because the user who has access to PowerShell can run any commands they like at the interactive prompt. The Execution Policy is not designed to control this—that job is left to the Windows Account Model. See this Microsoft article for further reading.

So, what if you are interested in preventing attackers from running scripts that the user hasn’t approved? Then you should ideally set the Execution Policy to “AllSigned.” The reality is that this will also have the effect of preventing many (if not most) users from running unsigned scripts too, because most won’t have the ability or motivation to sign their own scripts.

However—and it’s a big however— although AllSigned is the most restrictive Execution Policy, the problem is that it still risks running signed but malicious scripts.

Determined attackers will go to great lengths to ensure that their attacks are successful, and signed PowerShell scripts are certainly something that has been seen “in the wild.”

The Short Answer

By collecting the Windows Crypto API logs from the CAPI2 Event Log, you can detect signed PowerShell scripts being executed and use AI Engine to alert when a script runs that was signed by an unexpected publisher.

The Solution (or Long Answer!)

There are several steps to implementing this use case. First, collect logs from the CAPI2 log source. This log source can be found in the Windows Event Viewer.

Figure

This log is not enabled by default, so either right-click and enable or right-click, select properties and enable. (In this example, I also extended the default maximum log size from 1MB to 4MB in my environment.)

Figure

Then, create a new Log Source Type and set up the log source collection in LogRhythm.

Figure

Figure

The CAPI2 log source logs events in XML format, so regular collection does not return very much useful information. Fortunately, you can enable direct XML collection against the log source and collect the information you’re interested in.

Now, you are ready to start parsing the logs. Here is the set of base regexes for the CAPI2 log processing policy.

Figure

There are a number of sub-rules that go with these that will aid in more granular detection of the activities that were taking place. I can share these with anyone who is interested (just add a comment below), but I will also add them to KnowledgeBase in due course. In the interest of being concise, I won’t list them all here.

So having parsed the logs, what are you looking for? When a script is launched in PowerShell, the digital signature is checked. The certificate chain itself is built and validated. Eventually, if the certificate is valid and the signature matches the correct file contents, an EventID 81 with the result code zero is logged.

Figure

From this, you can see that a script was run under the PowerShell process by the administrator, and the signature was successfully verified. But you don’t know who the publisher of the script was just from this log.

There are a series of EventIDs logged (typically 80, 10, 11, 30, 90 and 81) when a PowerShell script’s digital signature is checked. These events are all linked by a TaskID, so you can track related events. EventID 11 contains the name of the script publisher, so you need to get hold of the corresponding event.

Figure

Here you can see the name of the publisher in the subject field. In this case, it was “PowerShell User.” (This is my own self-signed certificate.)

Now that you have all the pieces in place, you can create an AI Engine rule to alert on PowerShell scripts being run in your environment that have been signed by a publisher that you don’t trust.

Figure

Figure

Figure

You created a list called “Whitelisted PowerShell Certificates” where you can add the name of publishers you trust for this purpose.

Figure

Figure

The alarm gives you the user name, script name, path from which the script launched and the publisher name.

You can also raise an alarm where a script is digitally signed, but the signature cannot be validated for one reason or another. Of course, if the AllSigned configuration is chosen, the script will not execute, but this provides visibility of the attempt, which is also useful information.

Figure

Figure

You could also use a behavioral baselining rule or a list of allowed script names. Once you have the logs in the system, you can ask them whatever you like!

The Value

By using LogRhythm’s ability to collect and parse logs from any log source and adding insight into what those logs actually mean, you can get compensating controls around activities that otherwise might keep your CISO (or you!) awake at night.

To learn more about creating AI Engine rules, click the button below.

More on AI Engine