Configuring & Monitoring Verbose Powershell CLI Usage with Splunk UF - cfloquetprojects/homelab GitHub Wiki
Introduction
It's not often we defenders leave tools beloved by our adversaries embedded on systems they wish to compromise, but with such a powerful and prevalent tool, we aren't given much of a choice. PowerShell is a Windows command-line utility commonly used by attackers and sysadmins alike to gather information from a specific host or environment, and often readily available to be exploited for those already in your network.
In order to combat this issue head on, we will be leveraging domain-level group policy objects (GPOs) as well as the Splunk Universal Forwarder
agent to both transcribe and centralize logs from distinct Windows 10
systems on any & all PowerShell
commands.
Unfortunately, despite PowerShell
being so robust in its capabilities, by default it doesn't actually leave many artifacts behind on the localhost of it's own execution, let alone verbose transcripts of the different commands run or what their associated results were.
- We will be walking through enabling not only logging the
PowerShell
commands being run by a user on a given host, but also also full transcript of data being returned within that terminal to understand what information may have been yielded.
Resources
-
Splunk Conf2016: PowerShell Power Hell: Hunting For Malicious PowerShell With Splunk (Slides)
-
Splunk Conf2016: PowerShell Power Hell: Hunting for Malicious use of PowerShell (Video)
-
Mandiant Threat Research: Greater Visibility Through PowerShell Logging
-
Malware Archaeology: Windows PowerShell Logging Cheat Sheet
-
Splunkbase: DECRYPT2 App For Splunk
-
Splunkbase: Splunk Add-on for Microsoft Windows
-
Splunk Docs: Detecting Anomalous Behavior within UBA using Powershell Transcription and Script Block Logging
-
Microsoft Docs: Command Line Process Auditing (via GPOs)
-
Internet Archive: No Easy Breach: Challenges and Lessons Learned from an Epic Investigation
-
Splunk Docs: Admin Manual for Props.conf
Agenda:
In order for us to truly begin to "win" investigations into PowerShell
usage in our environment, we will need to accomplish the following, all of which will be covered in this lab:
-
Edit domain-level GPOs to enable the following different logging features:
- Module Logging (4103), in the context of PowerShell auditing, records the pipeline execution details (which includes variable initialization and command invocations), but doesn't reliably capture any & all commands executed, which is why we will also be enabling
Script Block Logging
and especiallyTranscription Logging
. - We can enable Script Block Logging (4104), which will record the input of every PowerShell command on the host, but if we really want the most verbose output we should turn on
transcription
, which will write not only the commands entered but also their respective results as the attacker sees them. - Lastly, and perhaps most importantly, is transcription, which creates a unique record of every
PowerShell
session, including all input and output text. The notable exception to what gets recorded here (which is recorded by Module and Script Block logging) is the contents of executed scripts, or outputs written to other destinations such as the file system.
- Module Logging (4103), in the context of PowerShell auditing, records the pipeline execution details (which includes variable initialization and command invocations), but doesn't reliably capture any & all commands executed, which is why we will also be enabling
-
Configure write-only permissions for domain-level users to
PowerShell
transcript folder -
Monitoring folder/files where
PowerShell
event logs will be stored using Splunks'Universal Forwarder
-
Using
props.conf
andregex
on theIndexer/Heavy Forwarder
instance in order to parse fields, as well as trim unnecessary information and reduce noise/license impact. -
Identifying malicious
PowerShell
using common TTPs mapped to the MITRE ATT&CK framework associated with this attack vector. -
Create advanced searches which leverage the
DECRYPT2
app (see resources) to decrypt encoded commands.
Pre-Flight Check:
-
We will be using essentially two distinct machines in todays lab, but this is built upon previous labs where we have configured
Active Directory
,Splunk Enterprise
, and other important infrastructure on servers that will not be covered in todays lab. -
At the very least, you'll need a dedicated domain controller as well as a domain-joined Win10 client, which will be used to deploy group policies to and monitor
PowerShell
activity on. -
The machines I am using involve a management server running on
Windows Server 2016
, with a Splunk Universal forwarder configured on it that has a separateDeployment Server
for installing/removing apps, but this is not entirely necessary and the edits we will do later can be done at$SPLUNK_HOME/etc/system/local/inputs.conf
.
Make sure you have an indexer
or heavy forwarder
configured to listening for the data that we will be sending to it prior to continuing as well.
Configuring Permissions for PowerShell Transcription Folder:
In order for us to collect transcribed PowerShell logs, we will need to define a folder path where the .txt
files which will be generated can be stored, which I have chosen to store in C:\Windows\Logs\powershell
💣 It's critical that (as shown in the screenshot below) we leave
Modify
permissions unchecked for this user group, as this is what essentially disallows log tampering.
[0]
Configuring Domain-Level GPOs for PowerShell Module, Script Block, and Transcription Logging:
First things first, on either our domain controller or dedicated management host (whichever has direct access to edit/modify existing domain-level group policy objects) within Server Manager
navigate to Tools > Group Policy Management
:
💣 Make sure you are logging into the device you wish to manage group policies using an account which is part of the
Domain Administrators
group within the AD domain you are managing. Otherwise, you will not be able to make any changes to domain-level group policy objects (GPOs).
[1]
Once we have our Group Policy Management
console open, navigate to your domain (which in my home lab is yellowstone.local, but in your environment is almost certainly different) navigate and right click to "Edit" the Default Domain Policy
, as shown in the screenshot below:
[2]
This will open up the specific (domain-level) Group Policy Editor
, which is how we will interact with and modify our GPOs via, but the changes we make can also be done at the registry level using an elevated terminal.
Navigate to Windows PowerShell
within Windows Components
as shown below, where we will be met with options to configure the different features that were discussed earlier, such as Module Logging
, Script Block Logging
, as well as Transcription
:
[3]
Double click (or right click and Edit
) first the Turn on Module Logging
setting where we can configure all PowerShell modules to be monitored, as represented by the *
, or what's often referred to as a wildcard.
[4]
As shown in the screenshot above be sure to Apply
your changes prior to either hitting OK
, or Next Setting
in order to move onto configuring Script Block Logging
, as shown in the screenshot below:
💡 Enabling invocation logging here basically logs events when the invocation of commands or scripts start or stop, which often gives additional information about when a malicious script started/stopped running, again bolstering our ability to create timelines based on these events.
[5]
Lastly, we need to turn on/configure PowerShell transcription, and configure a proper output directory (to a folder which has write-only permissions for all domain-level users, which we have done in a previous step):
💡 Invocation Headers are important to include because this is what allows us to get a start time for each terminal session, which helps during an incident response investigation to establish timelines etc.
[6]
Finally, your Windows PowerShell GPO settings at a domain level should look something like below, which you can push to all domain-joined clients using the gpupdate /force
command, also shown below:
[7]
[8]
Validating Proper Logging Configuration using PowerShell:
PS> $basePath = 'HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
PS> Set-ItemProperty $basePath -Name EnableScriptBlockLogging -Value "1"