From 724baa6c0aee19240eee6b7eb40cd22eacdd3574 Mon Sep 17 00:00:00 2001 From: PTah Date: Sat, 30 May 2026 10:20:57 +1000 Subject: [PATCH] feat: monitor RDS Shadow Control and WinRM inbound (warning alerts, 1.2.23-SAC) Co-authored-by: Cursor --- Login_Monitor.ps1 | 367 ++++++++++++++++++++++++++++- README.md | 2 +- ignore.lst.example | 11 +- login_monitor.settings.example.ps1 | 7 +- version.txt | 3 +- 5 files changed, 383 insertions(+), 7 deletions(-) diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index d12c565..85c4bde 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -80,7 +80,7 @@ $script:MonitorLoopInitialized = $false # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "1.2.22-SAC" +$ScriptVersion = "1.2.23-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" @@ -120,6 +120,17 @@ $RDGatewayEvents = @(302, 303) $RcmLogName = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" $RcmEventId = 1149 +# RDS Shadow Control (RCM/Operational): опасные теневые подключения с управлением +$EnableRcmShadowControlMonitoring = 1 +$RcmShadowControlEventIds = @(20506, 20507, 20510) + +# WinRM / Enter-PSSession inbound (удалённая PowerShell-сессия на этот хост) +$EnableWinRmInboundMonitoring = 1 +$WinRmLogName = 'Microsoft-Windows-WinRM/Operational' +$WinRmInboundShellEventIds = @(91) +$WinRmCorrelateSecurity4624 = 1 +$WinRm4624CorrelationWindowSeconds = 15 + $ExcludedProcesses = @( "HTTP", "HTTP/*", "W3WP.EXE", "MSExchange", "SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE", "OUTLOOK.EXE", "EXCHANGE", "EDGETRANSPORT", "STORE.EXE", @@ -1248,6 +1259,236 @@ function Format-Rcm1149Event { return $message } +function Test-MonitorFeatureEnabled { + param( + $Value, + [bool]$DefaultEnabled = $true + ) + if ($null -eq $Value) { return $DefaultEnabled } + if ($Value -is [bool]) { return $Value } + if ($Value -is [int] -or $Value -is [long]) { return ([int]$Value -ne 0) } + $s = ([string]$Value).Trim().ToLowerInvariant() + if ($s -in @('0', 'false', 'no', 'off')) { return $false } + return $true +} + +function Test-WinRmLogAvailable { + try { + $logExists = Get-WinEvent -ListLog $WinRmLogName -ErrorAction SilentlyContinue + return [bool]$logExists + } catch { + return $false + } +} + +function Get-RcmShadowEventInfo { + param($Event) + $eventData = @{ + TimeCreated = $Event.TimeCreated + EventId = [int]$Event.Id + ShadowerUser = '-' + TargetUser = '-' + SessionId = '-' + ShadowAction = 'control' + } + try { + $map = Get-EventDataMap -Event $Event + $eventData.ShadowerUser = Get-FirstNonEmptyMapValue -DataMap $map -Keys @( + 'Shadower', 'ShadowerUser', 'Admin', 'Administrator', 'UserName', 'SubjectUserName', 'Param1' + ) + if ([string]::IsNullOrWhiteSpace($eventData.ShadowerUser)) { $eventData.ShadowerUser = '-' } + $eventData.TargetUser = Get-FirstNonEmptyMapValue -DataMap $map -Keys @( + 'TargetUser', 'User', 'AccountName', 'TargetUserName', 'ConnectionUser', 'Param2' + ) + if ([string]::IsNullOrWhiteSpace($eventData.TargetUser)) { $eventData.TargetUser = '-' } + $sid = Get-FirstNonEmptyMapValue -DataMap $map -Keys @('SessionID', 'SessionId', 'Session', 'Param3') + if (-not [string]::IsNullOrWhiteSpace($sid)) { $eventData.SessionId = [string]$sid } + + if ($eventData.ShadowerUser -eq '-' -and $Event.Properties.Count -gt 0) { + $eventData.ShadowerUser = [string]$Event.Properties[0].Value + } + if ($eventData.TargetUser -eq '-' -and $Event.Properties.Count -gt 1) { + $eventData.TargetUser = [string]$Event.Properties[1].Value + } + if ($eventData.SessionId -eq '-' -and $Event.Properties.Count -gt 2) { + $eventData.SessionId = [string]$Event.Properties[2].Value + } + + $msg = [string]$Event.Message + if ($eventData.SessionId -eq '-' -and $msg -match '(?i)(?:session|сеанс)\s*(?:id\s*)?[:\s#]*(\d+)') { + $eventData.SessionId = $Matches[1] + } + switch ([int]$Event.Id) { + 20506 { $eventData.ShadowAction = 'control_started' } + 20507 { $eventData.ShadowAction = 'control_stopped' } + 20510 { $eventData.ShadowAction = 'control_permission' } + } + } catch { + Write-Log "Ошибка разбора RCM shadow $($Event.Id): $($_.Exception.Message)" + } + return $eventData +} + +function Format-RcmShadowControlEvent { + param( + [hashtable]$Info, + [string]$SecurityLogComputerName + ) + $logHost = $SecurityLogComputerName + if ([string]::IsNullOrWhiteSpace($logHost)) { $logHost = $env:COMPUTERNAME } + $hHost = (ConvertTo-TelegramHtml (Get-MonitorServerLabelWithIp)) + $hLog = (ConvertTo-TelegramHtml $logHost) + $hShadower = (ConvertTo-TelegramHtml $Info.ShadowerUser) + $hTarget = (ConvertTo-TelegramHtml $Info.TargetUser) + $hSid = (ConvertTo-TelegramHtml $Info.SessionId) + $hTime = (ConvertTo-TelegramHtml ($Info.TimeCreated.ToString('dd.MM.yyyy HH:mm:ss'))) + + $header = switch ($Info.ShadowAction) { + 'control_started' { '🎭 RDS SHADOW CONTROL — начато' } + 'control_stopped' { '🎭 RDS SHADOW CONTROL — остановлено' } + 'control_permission' { '🎭 RDS SHADOW CONTROL — разрешение выдано' } + default { '🎭 RDS SHADOW CONTROL' } + } + $message = "$header`r`n" + $message += "🏢 Сервер: $hHost`r`n" + $message += "👤 Администратор (shadow): $hShadower`r`n" + $message += "🎯 Сессия пользователя: $hTarget`r`n" + if ($Info.SessionId -ne '-') { + $message += "🔢 Session ID: $hSid`r`n" + } + $message += "🕐 Время: $hTime`r`n" + $message += "🔢 Event ID: $($Info.EventId) (RemoteConnectionManager)" + return $message +} + +function Get-SacTypeForRcmShadowEvent { + param([int]$EventId) + switch ($EventId) { + 20506 { return 'rdp.shadow.control.started' } + 20507 { return 'rdp.shadow.control.stopped' } + 20510 { return 'rdp.shadow.control.permission' } + default { return 'rdp.shadow.control.started' } + } +} + +function Get-WinRm91EventInfo { + param($Event) + $eventData = @{ + TimeCreated = $Event.TimeCreated + EventId = [int]$Event.Id + User = '-' + ResourceUri = '-' + SourceIP = '-' + LogonType = 0 + } + try { + $map = Get-EventDataMap -Event $Event + $eventData.User = Get-FirstNonEmptyMapValue -DataMap $map -Keys @( + 'user', 'User', 'UserName', 'AccountName', 'SubjectUserName' + ) + $eventData.ResourceUri = Get-FirstNonEmptyMapValue -DataMap $map -Keys @( + 'resourceUri', 'ResourceUri', 'shellId', 'ShellId', 'connection', 'Connection' + ) + if ([string]::IsNullOrWhiteSpace($eventData.User) -and $Event.Properties.Count -gt 0) { + $eventData.User = [string]$Event.Properties[0].Value + } + $msg = [string]$Event.Message + if ($eventData.ResourceUri -eq '-' -and $msg -match '(?i)ResourceUri:\s*(.+)$') { + $eventData.ResourceUri = $Matches[1].Trim() + } + } catch { + Write-Log "Ошибка разбора WinRM $($Event.Id): $($_.Exception.Message)" + } + if ([string]::IsNullOrWhiteSpace($eventData.User)) { $eventData.User = '-' } + if ([string]::IsNullOrWhiteSpace($eventData.ResourceUri)) { $eventData.ResourceUri = '-' } + return $eventData +} + +function Find-CorrelatedNetworkLogon4624 { + param( + [datetime]$AroundTime, + [string]$UsernameHint = '', + [int]$WindowSeconds = 15 + ) + $start = $AroundTime.AddSeconds(-1 * [Math]::Abs($WindowSeconds)) + $end = $AroundTime.AddSeconds([Math]::Abs($WindowSeconds)) + try { + $events = @(Get-WinEvent -FilterHashtable @{ + LogName = 'Security' + ID = 4624 + StartTime = $start + } -ErrorAction SilentlyContinue | Where-Object { $_.TimeCreated -le $end }) + } catch { + return $null + } + $best = $null + foreach ($ev in $events) { + $info = Get-LoginEventInfo -Event $ev + if ($info.LogonType -ne 3) { continue } + if ($info.SourceIP -eq '-' -or [string]::IsNullOrWhiteSpace($info.SourceIP)) { continue } + if (-not [string]::IsNullOrWhiteSpace($UsernameHint) -and $UsernameHint -ne '-') { + if (-not (Test-RdpMonitorUsernameMatchesToken -Username $info.Username -Token $UsernameHint)) { + continue + } + } + if ($null -eq $best -or $ev.TimeCreated -gt $best.TimeCreated) { + $best = [pscustomobject]@{ + Username = $info.Username + SourceIP = $info.SourceIP + LogonType = $info.LogonType + ProcessName = $info.ProcessName + TimeCreated = $ev.TimeCreated + } + } + } + return $best +} + +function Format-WinRmSessionEvent { + param( + [hashtable]$Info, + [string]$SecurityLogComputerName + ) + $logHost = $SecurityLogComputerName + if ([string]::IsNullOrWhiteSpace($logHost)) { $logHost = $env:COMPUTERNAME } + $hHost = (ConvertTo-TelegramHtml (Get-MonitorServerLabelWithIp)) + $hUser = (ConvertTo-TelegramHtml $Info.User) + $hIp = (ConvertTo-TelegramHtml $Info.SourceIP) + $hUri = (ConvertTo-TelegramHtml $Info.ResourceUri) + $hTime = (ConvertTo-TelegramHtml ($Info.TimeCreated.ToString('dd.MM.yyyy HH:mm:ss'))) + + $message = "⚠️ WinRM / Enter-PSSession — удалённая shell`r`n" + $message += "🏢 Сервер: $hHost`r`n" + $message += "👤 Пользователь: $hUser`r`n" + if ($Info.SourceIP -ne '-') { + $message += "🌐 IP источника: $hIp`r`n" + } + if ($Info.ResourceUri -ne '-') { + $message += "🔗 ResourceUri: $hUri`r`n" + } + $message += "🕐 Время: $hTime`r`n" + $message += "🔢 Event ID: $($Info.EventId) (WinRM Operational)" + return $message +} + +function Test-RdpMonitorNotifyDedup { + param( + [string]$Key, + [int]$WindowSeconds = 90 + ) + if ([string]::IsNullOrWhiteSpace($Key)) { return $false } + if (-not $script:NotifyDedupCache) { + $script:NotifyDedupCache = @{} + } + $now = Get-Date + if ($script:NotifyDedupCache.ContainsKey($Key)) { + $until = $script:NotifyDedupCache[$Key] + if ($now -lt $until) { return $true } + } + $script:NotifyDedupCache[$Key] = $now.AddSeconds($WindowSeconds) + return $false +} + function Get-MonitorServerLabel { $label = $null if (Get-Variable -Name ServerDisplayName -ErrorAction SilentlyContinue) { @@ -1757,8 +1998,14 @@ function Parse-RdpMonitorIgnoreListLine { if ($line -match '^(?i)(4740|lockout|блокир)\s*:\s*(.+)$') { $scopes = @('4740') $line = $Matches[2].Trim() + } elseif ($line -match '^(?i)(shadow|20506)\s*:\s*(.+)$') { + $scopes = @('20506', '20507', '20510') + $line = $Matches[2].Trim() + } elseif ($line -match '^(?i)(winrm|pssession|91)\s*:\s*(.+)$') { + $scopes = @('winrm') + $line = $Matches[2].Trim() } elseif ($line -match '^(?i)(all|\*)\s*:\s*(.+)$') { - $scopes = @('4624', '4625', '4740') + $scopes = @('4624', '4625', '4740', '20506', '20507', '20510', 'winrm') $line = $Matches[2].Trim() } if ([string]::IsNullOrWhiteSpace($line)) { return $null } @@ -2756,6 +3003,21 @@ function Start-LoginMonitor { Write-Log "Мониторинг 4740 задан для КД '$LockoutMonitorDomainController', но этот узел — $env:COMPUTERNAME (блокировки не отслеживаются)." } + if (Test-MonitorFeatureEnabled -Value $EnableRcmShadowControlMonitoring) { + if (Test-RcmLogAvailable) { + Write-Log "RDS Shadow Control: включён (RCM Operational IDs: $($RcmShadowControlEventIds -join ', '))." + } else { + Write-Log "RDS Shadow Control: включён в настройках, но журнал RCM недоступен." + } + } + if (Test-MonitorFeatureEnabled -Value $EnableWinRmInboundMonitoring) { + if (Test-WinRmLogAvailable) { + Write-Log "WinRM inbound (Enter-PSSession): включён (Operational IDs: $($WinRmInboundShellEventIds -join ', '); correlate 4624=$WinRmCorrelateSecurity4624)." + } else { + Write-Log "WinRM inbound: включён в настройках, но журнал WinRM Operational недоступен." + } + } + $script:MonitorStartedAt = Get-Date $script:HeartbeatStaleAlertActive = $false @@ -2777,13 +3039,19 @@ function Start-LoginMonitor { Write-Log "Рабочая станция: журнал Remote Connection Manager недоступен — уведомления только по Security 4624/4625 (LogonType 10). Проверьте, что включён удалённый рабочий стол." } + $rcmShadowMonitoringEnabled = (Test-MonitorFeatureEnabled -Value $EnableRcmShadowControlMonitoring) -and (Test-RcmLogAvailable) + $winRmMonitoringEnabled = (Test-MonitorFeatureEnabled -Value $EnableWinRmInboundMonitoring) -and (Test-WinRmLogAvailable) + $nextHeartbeatTime = (Get-Date).AddSeconds($HeartbeatInterval) $nextRotationCheck = Check-AndRotateLog $nextReportCheck = Check-AndSendDailyReport $lastCheckTime = (Get-Date).AddSeconds(-10) $lastGatewayCheckTime = (Get-Date).AddSeconds(-10) $lastRcmCheckTime = (Get-Date).AddSeconds(-10) + $lastRcmShadowCheckTime = (Get-Date).AddSeconds(-10) + $lastWinRmCheckTime = (Get-Date).AddSeconds(-10) $lastLockout4740CheckTime = (Get-Date).AddSeconds(-10) + if (-not $script:NotifyDedupCache) { $script:NotifyDedupCache = @{} } $monitorEvents = @(4624, 4625, 4648) while ($true) { @@ -3013,6 +3281,101 @@ function Start-LoginMonitor { } } + if ($rcmShadowMonitoringEnabled) { + $shadowEvents = Get-WinEvent -FilterHashtable @{ + LogName = $RcmLogName + ID = $RcmShadowControlEventIds + StartTime = $lastRcmShadowCheckTime + } -ErrorAction SilentlyContinue + + if ($shadowEvents) { + foreach ($event in $shadowEvents) { + if ($event.TimeCreated -le $lastRcmShadowCheckTime) { continue } + $sh = Get-RcmShadowEventInfo -Event $event + if ($sh.ShadowerUser -like '*$') { continue } + if (Test-RdpMonitorIgnoreListMatch -EventId ([string]$event.Id) -Username $sh.ShadowerUser ` + -ComputerName $sh.TargetUser -SourceIP '-') { + Write-Log "Skip shadow $($event.Id): Shadower=$($sh.ShadowerUser) Target=$($sh.TargetUser) — ignore.lst" + continue + } + $dedupKey = "shadow|$($event.Id)|$($sh.ShadowerUser)|$($sh.TargetUser)|$($sh.SessionId)" + if (Test-RdpMonitorNotifyDedup -Key $dedupKey -WindowSeconds 120) { + Write-Log "Notify dedup shadow $($event.Id): $dedupKey" + continue + } + $sacType = Get-SacTypeForRcmShadowEvent -EventId $event.Id + $msg = Format-RcmShadowControlEvent -Info $sh -SecurityLogComputerName $event.MachineName + Write-Log "Notify shadow $($event.Id): Shadower=$($sh.ShadowerUser) Target=$($sh.TargetUser) Session=$($sh.SessionId)" + Send-MonitorNotification -Message $msg ` + -EmailSubject "RDP Login Monitor: RDS Shadow $($event.Id)" ` + -SacEventType $sacType -SacSeverity 'warning' ` + -SacTitle "RDS Shadow Control $($event.Id)" ` + -SacSummary "Shadow $($event.Id) $($sh.ShadowerUser) -> $($sh.TargetUser)" ` + -SacDetails @{ + event_id_windows = [int]$event.Id + shadow_mode = 'control' + shadow_action = $sh.ShadowAction + shadower_user = $sh.ShadowerUser + target_user = $sh.TargetUser + target_session_id = $sh.SessionId + session_id = $sh.SessionId + } | Out-Null + } + $lastRcmShadowCheckTime = ($shadowEvents | Measure-Object -Property TimeCreated -Maximum | Select-Object -ExpandProperty Maximum).AddSeconds(1) + } + } + + if ($winRmMonitoringEnabled) { + $winRmEvents = Get-WinEvent -FilterHashtable @{ + LogName = $WinRmLogName + ID = $WinRmInboundShellEventIds + StartTime = $lastWinRmCheckTime + } -ErrorAction SilentlyContinue + + if ($winRmEvents) { + foreach ($event in $winRmEvents) { + if ($event.TimeCreated -le $lastWinRmCheckTime) { continue } + $wr = Get-WinRm91EventInfo -Event $event + if ($wr.User -like '*$') { continue } + if (Test-MonitorFeatureEnabled -Value $WinRmCorrelateSecurity4624) { + $corr = Find-CorrelatedNetworkLogon4624 -AroundTime $wr.TimeCreated ` + -UsernameHint $wr.User -WindowSeconds $WinRm4624CorrelationWindowSeconds + if ($null -ne $corr) { + $wr.SourceIP = $corr.SourceIP + if ($wr.User -eq '-' -and $corr.Username -ne '-') { $wr.User = $corr.Username } + $wr.LogonType = $corr.LogonType + } + } + if (Test-RdpMonitorIgnoreListMatch -EventId 'winrm' -Username $wr.User -SourceIP $wr.SourceIP) { + Write-Log "Skip WinRM $($event.Id): User=$($wr.User) IP=$($wr.SourceIP) — ignore.lst" + continue + } + $dedupKey = "winrm|$($event.Id)|$($wr.User)|$($wr.SourceIP)|$($event.RecordId)" + if (Test-RdpMonitorNotifyDedup -Key $dedupKey -WindowSeconds 90) { + Write-Log "Notify dedup WinRM $($event.Id): $dedupKey" + continue + } + $msg = Format-WinRmSessionEvent -Info $wr -SecurityLogComputerName $event.MachineName + Write-Log "Notify WinRM $($event.Id): User=$($wr.User) IP=$($wr.SourceIP)" + Send-MonitorNotification -Message $msg ` + -EmailSubject "RDP Login Monitor: WinRM shell (Enter-PSSession)" ` + -SacEventType 'winrm.session.started' -SacSeverity 'warning' ` + -SacTitle 'WinRM remote shell (Enter-PSSession)' ` + -SacSummary "WinRM 91 $($wr.User) from $($wr.SourceIP)" ` + -SacDetails @{ + event_id_windows = [int]$event.Id + user = $wr.User + source_ip = $wr.SourceIP + ip_address = $wr.SourceIP + resource_uri = $wr.ResourceUri + logon_type = $wr.LogonType + transport = 'winrm' + } | Out-Null + } + $lastWinRmCheckTime = ($winRmEvents | Measure-Object -Property TimeCreated -Maximum | Select-Object -ExpandProperty Maximum).AddSeconds(1) + } + } + if ($lockout4740Enabled) { $lockoutEvents = Get-WinEvent -FilterHashtable @{ LogName = 'Security' diff --git a/README.md b/README.md index ae2e5da..2c06b53 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ PowerShell-набор для мониторинга входов в Windows с ## Актуальная схема (рекомендуется) - Базовый путь установки: **`C:\ProgramData\RDP-login-monitor\`**. -- Основной скрипт: **`Login_Monitor.ps1`** — журнал Security **`4624`/`4625`** (логика зависит от типа ОС: рабочая станция или сервер/КД), при всплеске **`4625`** — **агрегированные оповещения** (два порога: IP+пользователь и только IP), при наличии журнала — **Remote Connection Manager `1149`** (часто актуально для РС с RDP), при роли **RD Gateway** — **`302`/`303`**, на **КД, где запущен монитор** (имя совпадает с **`$LockoutMonitorDomainController`**) — **`4740`** (блокировка УЗ + IP из IIS ActiveSync), **ежедневный отчёт** (активные сессии через `quser`), **heartbeat**, **ротация логов**, уведомления в Telegram и/или Email. +- Основной скрипт: **`Login_Monitor.ps1`** — журнал Security **`4624`/`4625`** (логика зависит от типа ОС: рабочая станция или сервер/КД), при всплеске **`4625`** — **агрегированные оповещения** (два порога: IP+пользователь и только IP), при наличии журнала — **Remote Connection Manager `1149`** (часто актуально для РС с RDP), **RDS Shadow Control** (`20506`/`20507`/`20510`, severity warning), **WinRM inbound / Enter-PSSession** (Operational `91`, severity warning), при роли **RD Gateway** — **`302`/`303`**, на **КД, где запущен монитор** (имя совпадает с **`$LockoutMonitorDomainController`**) — **`4740`** (блокировка УЗ + IP из IIS ActiveSync), **ежедневный отчёт** (активные сессии через `quser`), **heartbeat**, **ротация логов**, уведомления в Telegram и/или Email. - Установка задач: запуск **`Login_Monitor.ps1 -InstallTasks`** создаёт: - `RDP-Login-Monitor` (основной монитор), - `RDP-Login-Monitor-Watchdog` (контроль процесса каждые 5 минут). diff --git a/ignore.lst.example b/ignore.lst.example index 83132d6..67e44a1 100644 --- a/ignore.lst.example +++ b/ignore.lst.example @@ -6,7 +6,9 @@ # Область действия (префикс в начале строки, необязателен): # (по умолчанию) — только Security 4624/4625 # 4740: — только блокировка учётной записи (4740); для IP — любой IP из IIS -# all: — и 4624/4625, и 4740 +# shadow: — RDS Shadow Control (RCM 20506/20507/20510) +# winrm: / pssession: — WinRM inbound / Enter-PSSession (Operational 91) +# all: — 4624/4625, 4740, shadow, winrm # # Форматы правила (после префикса области): # user:domain\user @@ -26,5 +28,12 @@ # 4740:user:test.user # 4740:ip:203.0.113.50 +# --- только WinRM / Enter-PSSession inbound --- +# winrm:user:DOMAIN\jump-admin +# winrm:ip:192.168.160.50 + +# --- только RDS Shadow Control --- +# shadow:user:DOMAIN\helpdesk + # --- все перечисленные события --- # all:user:domain\noise_account diff --git a/login_monitor.settings.example.ps1 b/login_monitor.settings.example.ps1 index 2f80184..6959bb3 100644 --- a/login_monitor.settings.example.ps1 +++ b/login_monitor.settings.example.ps1 @@ -42,8 +42,13 @@ $SacApiKey = 'sac_UkOsAT3UWiQS54KK5OJPBDCSucysQDrKFju28wmYiz8' # $SacTlsSkipVerify = $false # $SacFallbackFailures = 5 # $false = не слать report.daily.rdp с агента (суточный отчёт только из SAC) -# Важно: только $false или 0/1 — строка "false" без $ ломает загрузку настроек! +# В settings.ps1 используйте 1/0 или $true/$false — не пишите голое false без $ $DailyReportEnabled = 1 + +# --- RDS Shadow Control + WinRM inbound (Enter-PSSession), severity warning --- +# $EnableRcmShadowControlMonitoring = 1 # RCM Operational 20506/20507/20510 +# $EnableWinRmInboundMonitoring = 1 # WinRM Operational 91 (+ correlate Security 4624) +# $WinRmCorrelateSecurity4624 = 1 # Проверка: powershell -File Login_Monitor.ps1 -CheckSac # --- Узкое исключение шумовых сетевых логонов (LogonType=3, Advapi) --- diff --git a/version.txt b/version.txt index 80ed66d..f5c215b 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1 @@ -1.2.22-SAC - +1.2.23-SAC