Короткий ответ
PowerShell — основной админ-инструмент и любимый канал для вредоносных скриптов. Без Script Block Logging (событие 4104 в Microsoft-Windows-PowerShell/Operational) и Module Logging (4103) вы видите только факт запуска, не содержимое. Включите оба в GPO на jump, серверах и станциях админов; транскрипты (Start-Transcript политикой) — на выделенный шару с ACL. Не выключайте логи «шумит 1С». Не отключайте Defender вместо логирования.
Событие 400 в том же журнале — старт движка. Это мало для расследования. WinRM-сессии тоже должны попадать в лог: настройка WinRM. Privileged скрипты — с jump, не с daily WS-042 под DA: разделение учёток.
Симптомы и как отличить
- Operational PowerShell пуст или только 400/403.
- Реестр
ScriptBlockLoggingотсутствует. - Инцидент «кто-то вызвал Invoke-*», содержимого нет.
- Транскрипт есть у админа локально в профиле и никуда не копируется.
| Что есть | Чего не хватает |
|---|---|
| 4688 powershell.exe | командлет внутри — нужен 4104 |
| AMSI/Defender детект | всё равно нужен журнал для разбора ложноположительных |
| Constrained Language | не замена логированию |
| PS 5.1 vs 7 | политика Windows PowerShell ≠ автоматически PS 7; смотрите оба, если используете 7 |
Возможные причины
- GPO не настроена, клиент на defaults.
- Политика только на User, а нужен Computer.
- Журнал Operational отключён / крошечный.
- Смотрят Classic «Windows PowerShell» log, не Operational.
- PS 7 (
pwsh) без своих политик. - Админ запускает
-Version 2.0где ещё доступно — обход (на 11/2022 v2 обычно нет; проверьте).
Диагностика
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging' -ErrorAction SilentlyContinue
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging' -ErrorAction SilentlyContinue
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription' -ErrorAction SilentlyContinue
Get-WinEvent -ListLog 'Microsoft-Windows-PowerShell/Operational' | Select-Object IsEnabled, MaximumSizeInBytes, RecordCount
Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' -MaxEvents 8 -ErrorAction SilentlyContinue |
Group-Object Id | Select-Object Name, CountПрогон:
Write-Output 'aaadmin-laps-test'
Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' -MaxEvents 15 |
Where-Object Id -eq 4104 | Select-Object TimeCreated, IdЕсли 4104 нет — политика не активна. Версия:
$PSVersionTable
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 -ErrorAction SilentlyContinueРешение
Сценарий A. GPO Windows PowerShell 5.1
Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell:
- Turn on PowerShell Script Block Logging = Enabled (желательно также Invoke logging / «Log script block invocation start/stop», если есть в ваших ADMX)
- Turn on Module Logging = Enabled, модули
*(или список, если сознательно сужаете —*для jump) - Turn on PowerShell Transcription = Enabled, каталог
\\fs01.contoso.example\ps-transcripts\%COMPUTERNAME%, Include invocation headers
gpupdate /forceУвеличьте Operational:
wevtutil sl Microsoft-Windows-PowerShell/Operational /ms:268435456256 МБ — ориентир для jump; подберите.
Сценарий B. PowerShell 7
Отдельные ADMX PowerShell 7 / политики Microsoft: включите script block logging для pwsh. Проверьте журналы PowerShell 7 (имена каналов зависят от установки — смотрите Event Viewer Applications and Services Logs). Не считайте, что GPO 5.1 покрывает 7.
Сценарий C. Объём и PII
4104 содержит текст скрипта. Могут попасть пароли, если админы так пишут. Регламент: секреты в Vault, не в командной строке. Retention и доступ к логам — как к privileged data. Не выключайте 4104 из-за паролей — выключите пароли в скриптах.
Сценарий D. Централизация
WEF: канал Microsoft-Windows-PowerShell/Operational, ID 4103, 4104, плюс 400 на jump. Фильтр по машинам OU-Admins, если канал узкий; на серверах — тоже, не только ПК.
На DC01 логировать каждый 4104 с интерактивных админ-сессий полезно, но объём большой: начните с jump и OU серверов, станции пользователей подключите выборочно. WS-042 бухгалтера с включённым Script Block Logging без WEF затрёт Operational за день. Транскрипты на \\fs01.contoso.example\ps-transcripts не заменяют 4104: файл можно удалить локальным админом. Сопоставляйте 4104 с 4624 privileged-учётки — так видно, что скрипт шёл не с daily-drive. PowerShell 7 на тех же хостах проверьте отдельно: молчание 5.1 Operational не значит, что pwsh не исполнялся.
Как проверить, что проблема устранена
На WS-042 и jump после gpupdate:
Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' -MaxEvents 20 | Where-Object Id -eq 4104EnableScriptBlockLogging = 1. Тестовая строка видна в 4104. Транскрипт появился на шаре (если включён). SIEM видит событие с jump.
Проверьте скрытый вызов powershell -enc на пилоте — 4104 должен содержать декодированный блок (поведение платформы).
Если не помогло
- Политика User выиграла/проиграла Computer — смотрите gpresult.
- Журнал не включён:
wevtutil sl ... /e:true. - Смотрите Classic log Windows PowerShell — не тот канал.
- AppLocker/WDAC режут скрипт до лога — смотрите и Code Integrity, и PowerShell.
- PSRemoting: логи на целевом хосте и на клиенте по-разному; собирайте оба в расследовании.
Не решайте шум полным off.
Профилактика
- Baseline jump: logging on, транскрипты, аудит входов.
- Запрет PowerShell 2.0 feature где ещё встречается на Server 2019.
- Обучение: не передавать пароли в
-Passwordв открытую. - Алерт на 4104 с подозрительными cmdlet (
Invoke-WebRequestк странным хостам) — на стороне SIEM, без выключения лога. - Часть hardening.
FAQ
Хватит ли только Transcription?
Нет. Файл на диске проще стереть, чем Operational+WEF. Транскрипт дополняет 4104, не заменяет.
Module Logging без Script Block
4103 видит вызовы модулей, не весь произвольный код. Нужны оба.
4104 слишком большой для SIEM
Собирайте с jump и серверов полностью; со станций пользователей — по риску/фильтру. Не с jump.
Constrained Language Mode вместо логов?
Дополнение. Админам на jump нужен Full Language + лог, иначе не работают инструменты.
Секреты в 4104 — нарушение?
Это аргумент не класть секреты в скрипты, плюс жёсткий ACL на SIEM. Выключение 4104 хуже для расследований.
Event 800 на Classic log
Старый канал. Для 5.1 якорь — Operational 4104. Classic можно оставить, не как единственный источник.