ADLOG-003: PowerShell Module Logging Enabled

Plataforma
Active Directory
Categoría
AD Logging & EDR Posture
Severidad
Medium
Pilar de Zero Trust
Visibility & Analytics (peso 1)
Fixtures de referencia
3
Cobertura de ramas
Observada: los fixtures prueban los veredictos que ejercitan
Procedencia
baseline

Qué comprueba

The check evaluates PowerShell Module Logging configuration through three layers. First, the registry layer: it reads HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging and confirms EnableModuleLogging is set to 1 (DWORD). It then enumerates the ModuleNames subkey, which is a set of string values where the value name and value data are both the module identifier ("*" means all modules; "Microsoft.PowerShell.Utility" means only that module). The check also reads the legacy preference key HKLM\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ModuleLogging for 32-bit hosts on 64-bit Windows and flags drift between the two views. Second, the GPO layer: it walks every linked Group Policy Object and parses the registry.pol file under \\<domain>\SYSVOL\<domain>\Policies\{GUID}\Machine\registry.pol for entries targeting the ModuleLogging key, so it can attribute the setting to a specific GPO and link scope rather than rely solely on the local resultant registry. This catches the common failure where a local administrator wrote the registry value by hand (which a future Group Policy refresh can overwrite) and where a GPO sets the value at one OU but a more specific OU does not. Third, the runtime layer: where a session can be opened, it queries the PSModuleAutoLoading and LogPipelineExecutionDetails state of the loaded modules via Get-Module | Select-Object Name,LogPipelineExecutionDetails to confirm the in-process flag matches the policy, and it samples the Microsoft-Windows-PowerShell/Operational channel for recent Event ID 4103 records to confirm the channel is actually receiving events. The check records: EnableModuleLogging (0/1/unset), ModuleNames (array), GpoSource (display name and DN of the GPO writing the value, or "Local" if no GPO matches), LegacyDrift (bool), OperationalChannelEnabled (bool), Last4103EventAge (timespan), and SuppressionRisk (true when the channel maximum size is below 100 MB or retention is set to overwrite, which makes log eviction trivial for an attacker generating noise).

Por qué importa

PowerShell is the default execution surface for Windows administration and the default offensive surface for everything from initial access to lateral movement. Empire, PowerSploit, PowerView, Nishang, Invoke-Mimikatz, Rubeus wrappers, Bloodhound collectors, and the majority of public red-team tradecraft are PowerShell modules or are loaded as in-memory script blocks by a PowerShell host. Without Module Logging, the defender sees a process-create event for powershell.exe or pwsh.exe with a command line that is frequently obfuscated, base64-encoded, or simply -EncodedCommand <blob>, and nothing else. The actual cmdlets, parameters, and pipeline data are invisible. Module Logging is the control that translates that opaque process into a per-cmdlet record: Invoke-WebRequest with the URL, Get-ADUser with the LDAP filter, Add-ADGroupMember with the principal, New-PSSession with the target host, Invoke-Command with the script block, Set-ItemProperty with the registry path and value. For DFIR, this is the difference between "PowerShell was used during the incident" and a reconstructable timeline. Three abuse patterns demonstrate the gap. First, credential theft via Get-Credential, Export-Clixml, and ConvertFrom-SecureString: without 4103, the defender cannot see the file path the credential was written to. Second, AD enumeration via the ActiveDirectory module: Get-ADUser -Filter * -Properties * pulls every user attribute including msDS-KeyCredentialLink and userPassword in 30 seconds, and without Module Logging the defender sees only ldap_search counters on the DC, not which attributes were requested by which host. Third, defensive evasion: Set-MpPreference -DisableRealtimeMonitoring $true and Remove-Item on the Windows Defender exclusion list show up in 4103 with the parameter values, but show up nowhere else outside of Defender-specific telemetry. Module Logging also costs little: the event volume is high but compressible, and the Microsoft-Windows-PowerShell/Operational channel can be sized to gigabytes or forwarded via Windows Event Forwarding to a central collector with sub-minute latency. The control is recommended by Microsoft, CISA, NSA, and the CIS PowerShell benchmark, and is one leg of the "PowerShell logging triad" alongside Script Block Logging (4104) and Transcription. ADLOG-003 fails closed when any of the three is missing.

Ruta de ataque

1. Reconnaissance under the radar: with Module Logging disabled, an attacker who has landed a PowerShell foothold (phishing payload, supply-chain implant, web shell) runs Import-Module ActiveDirectory; Get-ADUser -Filter * -Properties memberOf,servicePrincipalName,userAccountControl. The DC logs the LDAP search counters, but no 4103 event records the cmdlet or its parameters on the attacker host. The defender sees a PowerShell process with a short command line and nothing else. 2. Credential harvest: Invoke-Mimikatz, Out-Minidump, or a custom Get-LsassDump wrapper runs as an in-memory script block. Without Module Logging, the parameter bindings (target process, output path) are invisible. With Script Block Logging alone the defender sees the script text, but if the attacker uses AMSI bypasses or splits the payload across pipelines, even 4104 is incomplete; 4103 captures the actual cmdlet invocations after AMSI is bypassed because logging is at the pipeline binding stage. 3. Lateral movement: New-PSSession -ComputerName DC01 -Credential $cred; Invoke-Command -Session $s -ScriptBlock { ... } executes remotely. Without 4103, the source host shows only a TCP connection to DC01 on 5985 or 5986 and a WinRM client log entry; the script block executed on DC01 is not recoverable without DC-side logging that is itself dependent on Module Logging being enabled on DC01. 4. Persistence and defense evasion: New-ScheduledTaskAction, Register-ScheduledTask, Set-Service, New-Service, Add-MpPreference -ExclusionPath, and Set-MpPreference -DisableRealtimeMonitoring all complete silently. The Defender event log records the exclusion change only if Defender-specific logging is on, and the scheduled task XML lives in C:\Windows\System32\Tasks but the cmdlet that wrote it is unknown. 5. Cleanup: Clear-EventLog -LogName Security; wevtutil cl Microsoft-Windows-PowerShell/Operational. With Module Logging disabled there is no 4103 event for the Clear-EventLog cmdlet itself; with it enabled and a centrally forwarded channel, the clear is recorded upstream before the local log dies. 6. Long-term tradecraft: a sophisticated actor enumerates the ModuleLogging registry key on every host they land on. If the value is 0 or unset, they proceed in PowerShell. If it is 1, they switch to a non-PowerShell loader (C# via Add-Type executed before logging activates, or a native binary) to avoid the 4103 trail. ADLOG-003 closes the easy path and forces the attacker into harder-to-stage tradecraft, which is the entire purpose of PowerShell logging.

Cómo lo evalúa Guerrilla

Guerrilla evaluates Module Logging at the registry, GPO, and channel layers. Registry layer: Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name EnableModuleLogging and Get-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames" with .Property enumeration to read the module list. The 32-bit Wow6432Node mirror is read for drift detection. GPO layer: Get-GPO -All piped through Get-GPRegistryValue -Key "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" identifies which GPOs author the value and at which scope they are linked, which lets the check distinguish a domain-wide enforced policy from a one-off OU exception or a hand-edited local registry. The full Get-GPOReport -ReportType Xml output is parsed for the matching <RegistrySettings> blocks under the Computer Configuration node, so the check can record the source GPO display name and DN. Channel layer: Get-WinEvent -ListLog Microsoft-Windows-PowerShell/Operational reads MaximumSizeInBytes, LogMode (Circular vs AutoBackup vs Retain), and IsEnabled, and Get-WinEvent -FilterHashtable @{ LogName="Microsoft-Windows-PowerShell/Operational"; Id=4103; StartTime=(Get-Date).AddDays(-1) } -MaxEvents 1 confirms 4103 events are actually arriving (a common failure mode is the policy is set but the channel itself has been disabled or its ACL has been rewritten to deny SYSTEM write). Domain-wide assessment: where the check is run against a forest, it iterates all domain controllers, all member servers tagged Tier 0 (Get-ADComputer -SearchBase OU=Tier0,... or by group membership), and a sample of workstations, then reports per-host status and the percentage of in-scope hosts with the control fully enabled. Output rows include HostName, EnableModuleLogging (0/1/Unset), ModuleNames (array), GpoSource, LinkScope, OperationalChannelEnabled, OperationalChannelSizeMB, LogMode, Last4103EventAge, ScriptBlockLoggingEnabled (cross-reference), TranscriptionEnabled (cross-reference), and a Notes field that enumerates failure reasons.

Valor recomendado

Group Policy 'Turn on Module Logging' is Enabled with at least the '*' module name list. Registry: EnableModuleLogging = 1.

Remediación

Computer Configuration > Policies > Administrative Templates > Windows Components > Windows PowerShell > 'Turn on Module Logging' = Enabled. Add '*' to the Module Names list (logs all modules) or specifically Microsoft.PowerShell.* + the modules your environment uses for administration.

Veredictos probados con fixtures

Cada veredicto de esta tabla está probado por un fixture de referencia en la suite de pruebas que valida el módulo. La tabla se deriva de la última ejecución en verde; no puede editarse a mano.

Escenarios de veredicto de ADLOG-003
EscenarioVeredicto esperado
cleanPASS
known-badWARN
throttledNot Assessed

Mapeos a marcos de referencia

NIST SP 800-53
AU-2, SI-4
CIS AD Benchmark
9.2.2
MITRE ATT&CK
T1059.001