alphaspirit - Fotolia
PowerShell logging boosts security in the enterprise
Want to track any suspicious PowerShell activity across your network? Use these PowerShell logging techniques to curb potential threats that originate from scripts.
PowerShell gets a lot of bad publicity for being a very common tool for malware authors. Because of its deep integration with Windows and wide-ranging access to the operating system, PowerShell gives an attacker a number of ways to infiltrate and manipulate local and remote machines.
Some security experts have called to remove PowerShell from Windows or to reduce its capabilities, but that's not realistic. PowerShell is an indispensable tool for many system administrators and disabling its functionality would make management work much more difficult. By turning on PowerShell logging, enterprises can catch any suspicious scripting activity across the organization and learn from any security incidents that originated in PowerShell.
Types of PowerShell logging
There are three types of PowerShell logging: module, script block and transcription. You can configure the first two types as events in the Windows PowerShell event log. Transcription logs go to a text file.
Module logging keeps a record of pipeline execution events in PowerShell for specific modules. By default, modules in PowerShell do not log this, as you can see here:
Get-Module -ListAvailable | Select-Object Name,LogPipelineExecutionDetails
Name LogPipelineExecutionDetails
---- ---------------------------
Microsoft.PowerShell. False
Operation.Validation
PackageManagement False
Pester False
PowerShellGet False
PSReadline False
AppBackgroundTask False
To log the module SmbShare, run these PowerShell commands:
Import-Module SmbShare
(Get-Module SmbShare).LogPipelineExecutionDetails = $true
To illustrate what is inside these logs, run Get-SmbConnection from the PowerShell console and then check the event logs on the local machine.
Figure 1 shows the properties of event ID 4013 from this command. Event details include the parameters used with the command -- such as ThrottleLimit and AsJob -- and the hostname, PowerShell version, runspace ID and user who executed the command.
Setting up script block logging
Microsoft documentation calls a script block "a collection of statements or expressions that can be used as a single unit. A script block can accept arguments and return values." A simple way to show how a script block works is to use the Invoke-Command with the -ScriptBlock parameter:
Invoke-Command -ScriptBlock {Get-Process explorer}
Script block logging is one of the most useful aspects of PowerShell logging because it records obfuscated code to the event log. This is especially useful because the majority of PowerShell malware uses scrambled code to hide from IT teams.
Script block logging shows up in the event log as event ID 4104. Even without script block logging enabled, Windows still generates events that PowerShell flags as potentially malicious.
Figure 3 shows the result of a script block log generated using the following PowerShell command:
Invoke-Command -ScriptBlock {$a = "Variable";"This is a test $a"}
How to use transcription logging
PowerShell transcription logging writes any PowerShell commands and console output to a text file for analysis. Users start transcription logging manually with the Start-Transcript and Stop-Transcript commands in PowerShell or through a Group Policy/registry configuration.
A typical transcript file looks like this:
**********************
Windows PowerShell transcript start
Start time: 20180704143442
Username: VAGRANT-10\vagrant
RunAs User: VAGRANT-10\vagrant
Configuration Name:
Machine: VAGRANT-10 (Microsoft Windows NT 10.0.16299.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 6028
PSVersion: 5.1.16299.492
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.16299.492
BuildVersion: 10.0.16299.492
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20180704143459
**********************
PS C:\Windows\system32> Get-SmbConnection
**********************
PS C:\> exit
**********************
Windows PowerShell transcript end
End time: 20180704151126
**********************
The transcript shows the user running the PowerShell session and other helpful information, such as the process ID, PowerShell version, commands executed and timestamps.
Centralize PowerShell logging with Group Policy
Group Policy makes it easy to configure PowerShell logging for multiple machines. You can find these policies in the Group Policy editor at the following location: Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell
Here, you will see five settings: turn on module logging, turn on PowerShell script block logging, turn on script execution, turn on PowerShell transcription and set the default source path for Update-Help.
You can enable all the PowerShell logging types and two others: script execution and default source for Update-Help.
The "Turn on PowerShell transcription" setting should interest administrators who want to configure a central location for transcription logs. This setting writes all logs locally, so you can copy them to a folder with PowerShell.
For instance, once you set up this PowerShell script to run on each local machine, it creates a folder named C:\Windows\PSLogging and gives the local Users group permission to write to the share. It also adds a domain security group called Security Admins with full control to manage the logs.
$registryPath = "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\Transcription"
$Name = "EnableTranscripting"
$value = "1"
New-ItemProperty -Path $registryPath -Name $name -Value $value -PropertyType DWORD -Force
$Name = "EnableInvocationHeader"
$value = "1"
New-ItemProperty -Path $registryPath -Name $name -Value $value -PropertyType DWORD -Force
#Create directory and set permissions to write only for users
$Name = "OutputDirectory"
$value = "C:\Windows\PSLogging"
New-Item $value -type directory
$acl = Get-Acl $value
$acl.SetAccessRuleProtection($True, $False)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Users","Write,ReadAndExecute,AppendData", "ContainerInherit, ObjectInherit", "None", "Allow")
$rule2 = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\Security Admins","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)
$acl.AddAccessRule($rule2)
Set-Acl $value $acl
New-ItemProperty -Path $registryPath -Name $name -Value $value -PropertyType String -Force
Use PowerShell to copy the contents of the previous day's transcript log folder from each machine listed in Active Directory into a central folder. You can set this up as a scheduled task to run at the start of each day using the following script:
$YesterdaysLog = Get-Date -Date (Get-Date).AddDays(-1) -UFormat %Y%m%d
New-Item C:\AllLogs\$YesterdaysLog -ItemType Directory
$Computers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
foreach ($Computer in $Computers) {
Copy-Item "\\$Computer\C$\Windows\PSLogging\$YesterdaysLog\*" -Destination "C:\AllLogs\$YesterdaysLog\"
}
Last words about the benefits of PowerShell logging
PowerShell logging is easy to set up and a good security practice to protect the enterprise. It just takes a few Group Policy changes to start logging PowerShell activity on all your machines.
If the time comes when a malware infection hits your organization via PowerShell, these logs can help determine the origin and assist with the effort to minimize further attacks. For added protection, admins should investigate the use of security tools such as ELK Stack that can help identify malicious activity.