Примечание: всё далее описанное касается только PowerShell >= 2.0
Необходимые исходные условия.
Да, чудес не бывает, и для поиска причины блокировки пользователей потребуется некоторая настройка аудита безопасности на контроллерах домена. Должны быть включены следующие подкатегории аудита на контроллерах домена:
Категория аудита | Подкатегория аудита | Тип аудита | Интересующий нас eventID |
---|---|---|---|
Audit Account Logon Events (Вход учётной записи) | Kerberos Authentication Service (Аудит службы проверки подлинности Kerberos) | Отказ | 4771 Kerberos pre-authentication failed. |
Audit Logon Events (Вход/Выход) | Logon (Аудит входа в систему) | Отказ | 4625 An account failed to log on. |
Audit Logon Events (Вход/Выход) | Account Lockout (Аудит блокировки учётных записей) | Успех | 4740 Account locked |
Алгоритм поиска источника блокировки
- Определить какой контроллер является владельцем роли PDC-эмулятора
- Найти в журнале безопасности PDC-эмулятора событие с кодом 4740 в поле «TargetUserName», которого указано имя интересующего нас пользователя
- В поле «TargetDomainName» того же события найти имя контроллера домена, обслужившего авторизацию
- Найти в журнале безопасности контроллера, обслужившего авторизацию, событие с кодом 4625 (неуспешная NTLM авторизация) или 4771 (неуспешная kerberos авторизация)
- Из найденного события получить значения полей «IpAddress» — адрес ПК с которого была попытка авторизации
Этих действий будет достаточно для быстрого поиска ПК с вредоносным ПО, подбирающим пароли пользователей. Как правило достаточно быстро вычислить источник проблемы и изолировать его для дальнейшего расследования. Алгоритм поиска процесса непосредственно вызывающего блокировку пользователя сильно зависит от ПО, установленного на конечном ПК.
Используемые командлеты PowerShell
- Get-ADDomainController — для определения владельца роли PDC-эмулятора
- Get-WinEvent — «волшебный» командлет, благодаря которому и стал возможным быстрый поиск
В чём «магия» Get-WinEvent?
Во-первых он ищет события с конца и имеет параметр -MaxEvents, позволяющий найти только самое последнее событие или неколько самых последних событий.
Во-вторых он имеет прекрасный параметр -FilterHashtable, который позволяет очень гибко задать условия поиска события.
Скрипт поиска
Для себя я подготовил небольшой PowerShell скрипт.
На входе скрипт принимает либо имя пользователя, для которого необходимо найти источник блокировки, либо количество (по умолчанию — 1) последних заблокированных пользователей.
param ( $User, $Count = 1 ) $result = New-Object system.Data.DataTable "Locks" $col1 = New-Object system.Data.DataColumn Username,([string]) $col2 = New-Object system.Data.DataColumn DCFrom,([string]) $col3 = New-Object system.Data.DataColumn LockTime,([string]) $col4 = New-Object system.Data.DataColumn eventID,([string]) $col5 = New-Object system.Data.DataColumn SourceHost,([string]) $col6 = New-Object system.Data.DataColumn LogonType,([string]) $col7 = New-Object system.Data.DataColumn LogonProcessName,([string]) $col8 = New-Object system.Data.DataColumn FalureTime,([string]) $result.columns.add($col1) $result.columns.add($col2) $result.columns.add($col3) $result.columns.add($col4) $result.columns.add($col5) $result.columns.add($col6) $result.columns.add($col7) $result.columns.add($col8) $PDC = [string](Get-ADDomainController -Discover -Service PrimaryDC).Hostname $FilterHash = @{} $FilterHash.LogName = "Security" $FilterHash.ID = "4740" if ($User) { $FilterHash.data =$User $Count = 1 } $FilterHash2 = @{} $FilterHash2.LogName = "Security" $FilterHash2.ID = @("4625", "4771") Get-WinEvent -Computername $PDC -FilterHashtable $FilterHash -MaxEvents $Count | foreach { $Row = $result.NewRow() $Username = ([xml]$_.ToXml()).Event.EventData.Data | ? {$_.Name -eq “TargetUserName”} | %{$_."#text"} $DCFrom = ([xml]$_.ToXml()).Event.EventData.Data | ? {$_.Name -eq “TargetDomainName”} | %{$_."#text"} $LockTime = $_.TimeCreated $FilterHash2.data = $username Get-WinEvent -Computername $dcfrom -FilterHashtable $FilterHash2 -MaxEvents 3 | foreach { $Row = $result.NewRow() $Row.Username = $Username $Row.DCFrom = $DCFrom $Row.LockTime = $LockTime $Row.eventID = $_.ID $Row.SourceHost = ([xml]$_.ToXml()).Event.EventData.Data | ? {$_.Name -eq “IpAddress”} | %{$_."#text"} $Row.LogonType = ([xml]$_.ToXml()).Event.EventData.Data | ? {$_.Name -eq “LogonType”} | %{$_."#text"} switch ($Row.LogonType) { "2" {$Row.LogonType = "Interactive"} "3" {$Row.LogonType = "Network"} "4" {$Row.LogonType = "Batch"} "5" {$Row.LogonType = "Service"} "7" {$Row.LogonType = "Unlock"} "8" {$Row.LogonType = "NetworkCleartext"} "9" {$Row.LogonType = "NewCredentials"} "10" {$Row.LogonType = "RemoteInteractive"} "11" {$Row.LogonType = "CachedInteractive"} } $Row.LogonProcessName = ([xml]$_.ToXml()).Event.EventData.Data | ? {$_.Name -eq “LogonProcessName”} | %{$_."#text"} $Row.FalureTime = $_.TimeCreated $result.Rows.Add($Row) } } $result | Format-Table -AutoSize
Пример использования:
PS> Find-Locker.ps1 -User i.i.inanov PS> Find-Locker.ps1 -Count 10
Вместо P.S.
Да, есть Account Lockout and Management Tools с прекрасной утилитой LockoutStatus.exe, но она долго опрашивает все контроллеры домена (а некоторый из них могут быть и недоступны).
Предложенный скрипт никак не претендует на замену LockoutStatus.exe (у них совершенно разный принцип работы). Обычно я использую их вместе.
Готовый скрипт можно скачать с Google Drive: Find-Locker.ps1
ссылка на оригинал статьи http://habrahabr.ru/post/171701/
Добавить комментарий