From 6384a453954a5d190e264719c56adeed97a922bc Mon Sep 17 00:00:00 2001 From: PTah Date: Wed, 3 Jun 2026 15:08:20 +1000 Subject: [PATCH] =?UTF-8?q?fix:=20recognize=20auditpol=20RU=20Success+Fail?= =?UTF-8?q?ure=20as=20ot=D0=BA=D0=B0=D0=B7=20not=20only=20sboy=20(2.0.17-S?= =?UTF-8?q?AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- Login_Monitor.ps1 | 48 +++++++++++++++++++++++++++++++++-------------- README.md | 2 +- README_eng.md | 2 +- version.txt | 2 +- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index 6e84022..8df3e60 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -89,7 +89,7 @@ $script:SkipLogDetailLimit = 15 # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "2.0.16-SAC" +$ScriptVersion = "2.0.17-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" @@ -1139,13 +1139,18 @@ function Enable-SecurityAudit { function Test-SuccessAndFailureText { param([string]$Line) if ([string]::IsNullOrWhiteSpace($Line)) { return $false } - $w1 = Uc @(0x0443,0x0441,0x043F,0x0435,0x0445) - $w2 = Uc @(0x0438) - $w3 = Uc @(0x0441,0x0431,0x043E,0x0439) - $p1 = '(?i)' + [regex]::Escape($w1) + '\s+' + [regex]::Escape($w2) + '\s+' + [regex]::Escape($w3) - $p2 = '(?i)' + [regex]::Escape($w1) + '\s*' + [regex]::Escape($w2) + '\s*' + [regex]::Escape($w3) - if ($Line -match $p1) { return $true } - if ($Line -match $p2) { return $true } + $wSuccess = Uc @(0x0443,0x0441,0x043F,0x0435,0x0445) + $wAnd = Uc @(0x0438) + # RU auditpol: "Успех и сбой" (older builds) or "Успех и отказ" (common on Server 2016+ RU). + $failureWords = @( + (Uc @(0x0441,0x0431,0x043E,0x0439)), + (Uc @(0x043E,0x0442,0x043A,0x0430,0x0437)) + ) + foreach ($wFail in $failureWords) { + $p1 = '(?i)' + [regex]::Escape($wSuccess) + '\s+' + [regex]::Escape($wAnd) + '\s+' + [regex]::Escape($wFail) + $p2 = '(?i)' + [regex]::Escape($wSuccess) + '\s*' + [regex]::Escape($wAnd) + '\s*' + [regex]::Escape($wFail) + if ($Line -match $p1 -or $Line -match $p2) { return $true } + } if (($Line -match '(?i)Success') -and ($Line -match '(?i)Failure')) { return $true } return $false } @@ -1243,6 +1248,23 @@ function Enable-SecurityAudit { return $true } + # Locale-neutral subcategory GUIDs (Logon / Logoff). + function Ensure-LogonLogoffSubcategoriesByGuid { + $targets = @( + '0CCE9226-69AE-11D9-BED3-505054503030', + '0CCE9227-69AE-11D9-BED3-505054503030' + ) + foreach ($guid in $targets) { + $setArgs = ('/set /subcategory:{{{0}}} /success:enable /failure:enable' -f $guid) + $set = Invoke-AuditPol -Arguments $setArgs + if ($set.ExitCode -ne 0) { + Write-Log ("auditpol GUID SET FAIL (code {0}): {1}`n{2}" -f $set.ExitCode, $setArgs, $set.Text) + return $false + } + } + return $true + } + $preferRu = Test-RussianUiPreferred if ($preferRu) { @@ -1258,12 +1280,10 @@ function Enable-SecurityAudit { return } - # Logon/Logoff category GUID (not a user id). - Write-Log "Trying Logon/Logoff category set via known GUID (fallback)..." - $logonLogoffCategoryGuid = "69979849-797A-11D9-BED3-505054503030" - $guidSet = Invoke-AuditPol -Arguments ("/set /category:`"$logonLogoffCategoryGuid`" /success:enable /failure:enable") - if ($guidSet.ExitCode -ne 0) { - Write-Log ("auditpol GUID SET FAIL (code {0}):`n{1}" -f $guidSet.ExitCode, $guidSet.Text) + Write-Log "Trying Logon/Logoff subcategories via known GUIDs (locale-neutral fallback)..." + if (Ensure-LogonLogoffSubcategoriesByGuid) { + Write-Log "Audit policy (GUID): OK for Logon/Logoff subcategories." + return } Write-Log "WARNING: could not configure logon/logoff auditing via auditpol automatically. The script will continue; check audit policy in local/domain GPO." diff --git a/README.md b/README.md index f0dfca9..268adf6 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Get-Content "C:\ProgramData\RDP-login-monitor\Logs\login_monitor.log" -Tail 60 - **Локальные настройки RDP-монитора** вынесены в **`login_monitor.settings.ps1`** (образец **`login_monitor.settings.example.ps1`**). При автообновлении **`Login_Monitor.ps1`** с шары секреты и параметры КД **не слетают**. Deploy при отсутствии settings создаёт файл один раз из example на шаре. - **Кодировка `.ps1`**: в репозитории добавлены `.editorconfig` и `.gitattributes`, чтобы `*.ps1` по умолчанию сохранялись как **UTF-8 with BOM** и с **CRLF** (это сильно снижает “кракозябры” и ошибки парсинга PowerShell). - **Кодировка логов**: `login_monitor.log` / `watchdog.log` пишутся как **UTF-8 с BOM** (и при необходимости BOM добавляется к уже существующему файлу), чтобы в **FAR/старых просмотрщиках** не было ситуации “в консоли нормально, а в файле РЈРІРµ…” из‑за неверной авто-кодировки. -- **`auditpol` на русской Windows**: настройка/проверка аудита опирается на категорию **`Вход/выход`** и подкатегории **`Вход в систему` / `Выход из системы`** (ожидается строка **`Успех и сбой`**). Это устраняет ошибки вида `0x00000057` из‑за несуществующего на RU ОС имени `Logon`. +- **`auditpol` на русской Windows**: настройка/проверка аудита опирается на категорию **`Вход/выход`** и подкатегории **`Вход в систему` / `Выход из системы`** (ожидается **`Успех и сбой`** или **`Успех и отказ`** — формулировка зависит от сборки ОС). Это устраняет ошибки вида `0x00000057` из‑за несуществующего на RU ОС имени `Logon`. - **Стабильность**: `auditpol` вызывается по полному пути `%SystemRoot%\System32\auditpol.exe` (без зависимости от PATH), stdout+stderr объединяются через `ProcessStartInfo`. - **Агрегация 4625 (брутфорс)**: при включённом `$FailedLogonRateLimitEnabled` — уровень 1: **5** неудачных попыток за **60** с с одного источника для **одной** учётной записи (IP+user); уровень 2: **12** попыток за **60** с с одного IP (несколько логинов). Пока порог не достигнут — поштучные 4625; при всплеске — сводные алерты, одиночные подавляются. Параметры в начале `Login_Monitor.ps1`. Автоблокировка IP не выполняется. - **Exchange Mail Security** (`Exchange-MailSecurity.ps1`): на **сервере Exchange** — очереди, пересылка на внешние адреса, watchdog. Руководство: **[Docs/exchange-mail-security.md](Docs/exchange-mail-security.md)**. GPO **`Deploy-LoginMonitor.ps1`** на MailServer ставит тот же RDP-монитор и дописывает WinRM/4624 noise в **`login_monitor.settings.ps1`**; **`Deploy-DomainMonitors.ps1 -Target Exchange`** — отдельно. diff --git a/README_eng.md b/README_eng.md index 2a7fc29..16376ab 100644 --- a/README_eng.md +++ b/README_eng.md @@ -18,7 +18,7 @@ PowerShell toolkit for monitoring Windows logons with Telegram and/or Email (SMT - **`.ps1` encoding**: `.editorconfig` and `.gitattributes` encourage **`*.ps1`** as **UTF-8 with BOM** and **CRLF**, reducing mojibake and PowerShell parse issues. - **Log encoding**: `login_monitor.log` / `watchdog.log` are written as **UTF-8 with BOM** (BOM is applied to existing files if missing) so viewers like **FAR Manager** do not mis-detect encoding. -- **`auditpol` on Russian Windows**: auditing checks use the **`Вход/выход`** category and **`Вход в систему` / `Выход из системы`** subcategories (expect **`Успех и сбой`**), avoiding errors such as `0x00000057` when English names like `Logon` are absent on a localized OS. +- **`auditpol` on Russian Windows**: auditing checks use the **`Вход/выход`** category and **`Вход в систему` / `Выход из системы`** subcategories (expect **`Успех и сбой`** or **`Успех и отказ`**, depending on OS build), avoiding errors such as `0x00000057` when English names like `Logon` are absent on a localized OS. - **Stability**: `auditpol` is invoked via full path `%SystemRoot%\System32\auditpol.exe` (no PATH dependency); stdout and stderr are merged via `ProcessStartInfo`. - **`4625` burst alerts**: when `$FailedLogonRateLimitEnabled` is true — tier 1: **5** failures in **60** s per **IP+user**; tier 2: **12** in **60** s per **IP** (spray). Below thresholds, individual `4625` alerts are sent; during a burst, aggregated alerts replace per-event noise. No automatic IP blocking. Tune at the top of `Login_Monitor.ps1`. - **Exchange Mail Security** (`Exchange-MailSecurity.ps1`): Exchange server only — queues, external forwarding, watchdog. See **[Docs/exchange-mail-security.md](Docs/exchange-mail-security.md)**. diff --git a/version.txt b/version.txt index 9fc0243..c480f60 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.16-SAC +2.0.17-SAC