Как отслеживать важные события безопасности Windows с помощью PowerShell


Многие организации полагаются на технологии Microsoft, чтобы выполнять работу. В то же время угрозы акторы могут использовать операционные системы, такие как Windows. К счастью, Windows записывает события безопасности ОС, чтобы помочь вам выявить это поведение.

События безопасности, созданные Windows, служат важным ресурсом в процессе реагирования на инциденты. Инструменты, такие как Просмотр событий Windows от Microsoft, предоставляют вам необходимый доступ для просмотра захваченных событий, но обнаружить аномалии путем ручного пролистывания перегруженного журнала нереально.

В этом сообщении вы узнаете, как выявить потенциальные нарушения безопасности в Windows, изучив политики аудита, журналы событий Windows и анализируя события безопасности с помощью PowerShell.

Предварительные требования

Эта статья предназначена для передачи информации, которая научит вас анализу событий безопасности Windows с помощью PowerShell. Если вы хотите следовать за демонстрациями, вам понадобятся:

  • A Windows 10+ PC – This PC will be used to generate and track down potential security events in the event log. This tutorial will be using Windows PowerShell 5.1.
  • Права администратора на компьютере под управлением Windows
  • A PowerShell code editor such PowerShell ISE or Visual Studio (VS) Code.

Где Windows хранит события безопасности

Когда выполняется действие в операционной системе Windows, Windows регистрирует его как событие в одном или нескольких журналах событий. Журналы событий Windows хранятся в файловой системе по умолчанию в каталоге %SystemRoot%\system32\winevt\logs. Это местоположение можно изменить, изменив соответствующий подраздел реестра EventLog.

Если вы хотите узнать, где хранятся наиболее значимые журналы событий (Application, Security и System) в вашей системе, скопируйте и вставьте следующий код в консоль PowerShell или сохраните его как сценарий.

Чтобы получить доступ к местоположению хранения файла журнала Security, выполните код от имени администратора.

#Представьте журналы приложений, безопасности и системы в виде массива.
 $arrLogs = @(
     "Application"
     "Security"
     "System"
 )
 #Используйте командлет ForEach-Object для обработки каждого соответствующего журнала с помощью командлета Get-ItemProperty.
 $arrLogs | ForEach-Object {
     #Используйте командлет Get-ItemProperty для вывода настроенного пути к файлу для журнала приложений, безопасности и системы.
     Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\$_ -Name File | Select-Object PSChildName,File
 }

На следующем скриншоте показан ожидаемый вывод кода, отображающий имя и местоположение хранения файлов журналов для Application, Security и System.

Application, Security, and System audit log location

Политики аудита: Определение событий для записи

По умолчанию, Windows не захватывает все события безопасности, которые могут понадобиться для обнаружения или расследования нарушений. Чтобы контролировать, что Windows записывает и что не записывает, необходимо определить и применить политики аудита. Политика аудита – это набор инструкций, передаваемых Windows, которые указывают ей, какие события записывать.

Существует несколько способов назначения и работы с политиками аудита, такими как Политика группы. Политика группы хорошо работает, если вам необходимо применить политики аудита на нескольких компьютерах. Но в этой статье вы будете работать только с одним устройством, поэтому будете использовать инструмент auditpol. Инструмент auditpol поставляется с Windows и позволяет находить и устанавливать политики аудита в системе Windows.

Поиск политик аудита

Например, чтобы найти статус всех политик аудита в вашей системе Windows, используйте параметр /get, как показано ниже. Использование параметра /category, за которым следует символ подстановки, позволяет auditpol найти статус всех политик аудита, а не только одной, соответствующей определенной категории или подкатегории.

#Получить конфигурацию аудита системы.
auditpol /get /category:*

На следующем снимке экрана показана усеченная версия ожидаемого вывода кода, отображающая категорию аудита Управление учетными записями, подкатегории и статус (Настройка).

Audit policy category, subcategory, and configuration

A Setting that is configured as No Auditing means that all events associated with that audit policy subcategory will not be logged.

Настройка аудита политик

Инструмент auditpol может делать больше, чем просматривать настройки политики аудита. Он также может их изменять с помощью команды auditpol /set. Чтобы продемонстрировать будущие разделы в этом руководстве, откройте консоль PowerShell от имени администратора и выполните нижеприведенную команду. Эта команда начинает регистрировать все события (успешные и неудачные), которые являются частью подкатегории Вход в систему.

Настройка подкатегории Вход в систему заставляет вашу систему регистрировать события:

#Установите события входа в систему для записи действий успешного/неуспешного выполнения.
auditpol /set /subcategory:"Logon" /success:enable /failure:enable

Существует множество ресурсов, доступных для помощи в настройке аудита в соответствии с лучшими практиками, включая Стандарты центра интернет-безопасности (CIS), и Руководства по технической реализации безопасности (STIG) Агентства информационной безопасности обороны (DISA), а также руководство, опубликованное Microsoft.

Генерация журналов ошибок входа для анализа

Эта статья будет руководством и предполагает, что вы будете следовать за ней. Если вы настроили Windows для аудита событий входа в систему выше, давайте сейчас сгенерируем некоторые события безопасности для последующего анализа. Более конкретно, давайте сгенерируем 35 неудачных попыток входа, которые будут записаны в журнале безопасности вашей системы, чтобы имитировать атаки методом перебора.

1. Откройте ваш любимый редактор кода.

2. Скопируйте следующий код и вставьте его в редактор кода. Этот фрагмент кода пытается открыть процесс PowerShell.exe, используя командлет Start-Process, используя фиктивные имена пользователей и пароли.

#Определите 5 имен пользователей для записи как неудачи входа.
 $arrUsers = @(
     "AtaBlogUser1"
     "AtaBlogUser2"
     "AtaBlogUser3"
     "AtaBlogUser4"
     "AtaBlogUser5"
 )
 #Переберите имена пользователей с помощью ForEach-Object, чтобы сгенерировать неудачу входа для каждого из них.
 $arrUsers | ForEach-Object {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential($_, $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
 }
 #Сгенерируйте 30 неудач входа для пользователя AtaBlogUser.
 $i = 0
 Do {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential("AtaBlogUser", $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
     $i++
 } Until ($i -eq 30)

3. Сохраните сценарий PowerShell как Invoke-BogusEvents.ps1 или любое другое имя, которое вы хотите, и выполните сценарий.

При выполнении вы заметите ожидаемую ошибку, повторенную 35 раз, указывающую Имя пользователя или пароль неверны.

Authentication failure due to incorrect user name or password.

Если вы не получаете ожидаемый вывод, убедитесь, что служба вторичного входа находится в состоянии Running.

Доступ к событиям Windows с помощью PowerShell

Теперь, когда вы уверены, что у вас есть как минимум 35 событий безопасности Windows, давайте изучим, как их найти с помощью командлета Get-WinEvent в PowerShell.

Вам может быть знаком командлет Get-EventLog в PowerShell, который также используется для доступа к журналу событий программно. Get-EventLog использует устаревший интерфейс Win32 Application Programming Interface (API), который не будет обсуждаться в этом сообщении.

Откройте консоль PowerShell от имени администратора и вызовите cmdlet Get-WinEvent, передав ей параметры FilterHashtable и MaxEvents, как показано ниже.

Команда ниже запрашивает журнал безопасности вашей системы (LogName='Security') для события с идентификатором 4625 (ID=4625) и возвращает первые 10 новых экземпляров (MaxEvents 10).

#Фильтр журнала безопасности для первых 10 экземпляров события с идентификатором 4625
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 10

Если успешно, вы должны увидеть вывод, аналогичный следующему:

10 instances of Event ID 4625

Доступ к свойствам событий с помощью Get-WinEvent

В предыдущем разделе вы использовали Get-WinEvent, чтобы просматривать события безопасности Windows на высоком уровне, но в событии Windows содержится гораздо больше информации. Каждое событие Windows имеет ценные свойства, которые можно использовать для более глубокого анализа.

События Windows в формате XML

Когда Windows записывает событие, оно сохраняется в формате XML. Если так, то почему ваша команда Get-WinEvent возвращает типичные объекты PowerShell? Cmdlet Get-WinEvent считывает собственный интерфейс Windows API и переводит события в объекты PowerShell для расширенного функционала.

Каждое событие Windows имеет различные атрибуты, следующие определенной XML-схеме или структуре.

Ниже вы увидите, что каждое событие следует определенной структуре с тремя атрибутами:

  • имя – Имя свойства
  • inType – Определение типа ввода или как событие принимает значение
  • outputType – Определение типа вывода или как событие записывается

Поиск шаблонов XML событий с помощью PowerShell

Как упоминалось ранее, каждое событие безопасности Windows хранится в формате XML и имеет определенную схему, но как выглядит эта схема? Давайте выясним.

В одном из предыдущих разделов вы создали несколько событий с ID 4625 в журнале событий безопасности. Этот тип события имеет специфические атрибуты, которые применяются только к нему. Чтобы найти эти атрибуты и посмотреть, как выглядит шаблон:

1. Откройте консоль PowerShell от имени администратора, если у вас ее еще нет открыто.

2. Запустите Get-WinEvent еще раз, но на этот раз используйте параметр ListProvider, указав провайдер, который Windows использует для записи событий в журнал событий безопасности, и верните только свойство Events.

Свойство Events содержит все события, которые были записаны провайдером списка, и предоставляет шаблон XML для каждого из этих событий.

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events
Get Win Event List Provider

3. Теперь, когда у вас есть код для поиска шаблонов для всех типов событий, сузьте поиск, вернув только событие, связанное с ID 4625.

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625

4. Когда вы возвращаете только тип события входа в систему с ID 4625, ограничьте это только показом свойства Template как показано ниже.

#Получение шаблона XML события для свойств события с ID 4625.
 ((Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625).Template

Следующий снимок экрана показывает усеченную версию вывода кода, определяя имя свойства события, тип ввода и тип вывода. Вы можете видеть, что событие с ID 4625 имеет свойства с различными определениями ввода и вывода.

На следующем снимке экрана выделено свойство SubjectUserSid события с ID 4625. Это конкретное событие принимает тип ввода (inType) win:SID и отображает вывод (outType) в виде строки (string), так как он сохраняется в журнале безопасности.

XML template example

Как PowerShell переводит XML в объекты

Теперь, когда вы увидели, как Windows хранит события в формате XML и как просматривать эти шаблоны в PowerShell, давайте рассмотрим, как PowerShell переводит этот XML в объекты.

1. Запустите команду Get-WinEvent снова, чтобы вернуть наше событие с ID 4625. До сих пор здесь нет ничего нового. Обратите внимание, что PowerShell показывает только четыре свойства: TimeCreated, Id, LevelDisplayName и Message.

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1
Get-WinEvent FilterHashtable

По умолчанию cmdlet Get-WinEvent не возвращает все атрибуты из источника данных XML события в виде объекта PowerShell.

2. Теперь направьте вывод вышеуказанной команды в cmdlet Select-Object и укажите параметр Property, передав значение, чтобы показать все свойства.

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1 | Select-Object -Property *

Обратите внимание, что PowerShell скрывал множество различных свойств. Более конкретно, свойство с именем Properties. Свойство Properties содержит значение каждого атрибута события, которое вы видели ранее в шаблоне XML.

Powershell hiding Properties

3. Ограничьте вывод команды Get-WinEvent выделением свойства Properties. Это свойство хранит все свойства события, а не свойства объекта PowerShell, в виде массива.

# Вывод массива свойств события для первого экземпляра события с ID 4625
 $eventProperties = (Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1).properties
 $eventProperties

Слева на скриншоте выше представлен вывод вышеуказанной команды. Массив содержит значения для каждого из атрибутов XML в шаблоне XML справа на скриншоте.

Вывод кода на скриншоте сообщает, что произошла ошибка аутентификации для пользователя AtaBlogUser (TargetUserName) с системы Desktop-XXXXX (WorkstationName) с использованием IP-адреса ::1 (IpAddress).

Expected output correlating property values to Event ID 4625’s XML template.

Возможно, вы хотите вернуть только значение для свойства события TargetUserName. Поскольку вы уже сохранели все свойства события в переменную с именем $eventProperties, обратитесь к пятому индексу, который содержит значение для TargetUserName.

Вы должны обратиться к свойству value на объекте индивидуального свойства события, чтобы вернуть только значение (AtaBlogUser). $eventProperties[5].value

$eventProperties[5].value
Event attribute property positions

Практики, описанные в этом разделе, будут использоваться в последующих разделах для выявления попытки подбора пароля, которую вы имитировали ранее в этом посте.

Обнаружение Попытки Брутфорс-атаки

Теперь вы готовы использовать свои навыки PowerShell, чтобы выследить атаку методом грубой силы, которую вы воссоздали ранее в этом посте! Давайте проверим ваши навыки, имитируя, как может выглядеть отслеживание атаки методом грубой силы в определенный период времени.

Предположим, что вам поступило уведомление о случившемся инциденте, где ваша организация считает, что кто-то пытается использовать учетную запись администратора для входа на важный сервер под управлением Windows. Эта активность началась вчера. Вам нужно выяснить количество событий с ID 4625: Аккаунт не смог войти, произошедших за последние 24 часа, и определить тип входа для каждого события.

1. Найдите все события с ID 4625 (ID=4625) в журнале безопасности Windows (LogName="Security") за последние 24 часа (StartTime=((Get-Date).AddDays(-1).Date), заканчивая текущим временем (Get-Date).

$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1));EndTime=(Get-Date)}

2. Теперь подсчитайте все события, хранящиеся в переменной, чтобы определить, есть ли больше неудачных попыток входа, чем ожидалось.

$events.Count

Теперь вы должны видеть числовое значение, указывающее количество раз, когда событие с ID 4625 было найдено в журнале безопасности за последние 24 часа.

3. Таким образом, вы установили, что произошла атака методом грубой силы. Теперь отследите больше информации об этих событиях безопасности Windows. Для этого верните только атрибуты из каждого интересующего вас события.

Как уже упоминалось ранее, каждое значение для определенного события хранится в массиве с определенным индексом. Интересные свойства событий для этой демонстрации приведены ниже.

  • TargetUserName Индекс: [5]
  • LogonType Индекс: [10]
  • WorkstationName Индекс: [13]
  • IpAddress Индекс: [19]

Приведенный ниже образец кода считывает каждый объект в переменной $events, собирает только интересующие свойства и объединяет их в одну строку.

#Извлеките свойства событий TargetUserName, LogonType, WorkstationName и IpAddress из всех экземпляров события с идентификатором 4625 за последние 24 часа.
 $events | ForEach-Object {
     ## Обратитесь к свойству объекта свойства
     ## Верните только значение индексов 5,10,13 и 19 из массива свойств
     ## Объедините все значения вместе, объединив их запятой
     $_.properties[5,10,13,19].value -join ", "
 }

На следующем скриншоте показана усеченная версия ожидаемого вывода кода, подробно описывающая список, разделенный запятыми, TargetUserName, LogonType, WorkstationName и IpAddress.

A truncated version of the code’s output, detailing TargetUserName, LogonType, WorkstationName, and IpAddress property values.

4. Как вы видели в предыдущем шаблоне XML, у шаблона события с идентификатором 4625 есть атрибут LogonType. Этот атрибут указывает метод, с помощью которого учетная запись пыталась аутентифицироваться. После дальнейшего изучения вы заметили, что значение LogonType иногда отличается.

LogonType attribute

Значение LogonType – это числовое значение от 2 до 11, но что это означает? Вы проводите некоторое исследование и узнаете, что означает каждое значение.

2 – Интерактивный – Пользователь вошел на этот компьютер.

3 – Сетевой – Пользователь или компьютер вошли на этот компьютер из сети.

4 – Пакетный – Тип входа пакета используется серверами пакетов, где процессы могут выполняться от имени пользователя без его прямого участия.

5 – Служба – Служба была запущена Менеджером управления службами.

7 – Разблокировка – Этот рабочий стол был разблокирован.

8 – NetworkCleartext – Пользователь вошел на этот компьютер из сети. Пароль пользователя был передан пакету аутентификации в нехешированной форме. Встроенные аутентификационные пакеты все хешируют учетные данные перед их отправкой по сети. Учетные данные не передаются по сети в открытом виде (также называемом чистым текстом).

9 – НовыеУчетныеДанные – Вызывающий клонировал свой текущий токен и указал новые учетные данные для исходящих соединений. Новая сеанс входа в систему имеет тот же локальный идентификатор, но использует другие учетные данные для других сетевых соединений.

10 – RemoteInteractive – Вызывающий клонировал свой текущий токен и указал новые учетные данные для исходящих соединений. Новая сеанс входа в систему имеет тот же локальный идентификатор, но использует другие учетные данные для других сетевых соединений.

11 – CachedInteractive – Пользователь вошел на этот компьютер с сетевыми учетными данными, которые были сохранены локально на компьютере. Контроллер домена не был обращен для проверки учетных данных.

Сейчас, когда у вас есть хорошее понимание каждого LogonType, вместо того чтобы видеть числовое значение в выводе, вы хотите более описательную строку. Для создания “карт” в PowerShell используйте хэш-таблицу.

$logonTypes = @{
     [uint32]2 = "Interactive"
     [uint32]3 = "Network"
     [uint32]4 = "Batch"
     [uint32]5 = "Service"
     [uint32]7 = "Unlock"
     [uint32]8 = "NetworkCleartext"
     [uint32]9 = "NewCredentials"
     [uint32]10 = "RemoteInteractive"
     [uint32]11 = "CachedInteractive"
 }

5. Совместите Get-WinEvent и хэш-таблицу LogonType с ForEach-Object, чтобы создать сценарий, который вернет только нужные вам свойства с удобным для пользователя значением LogonType, как показано ниже. Команда Format-Table улучшает удобочитаемый вывод, форматируя ответ PowerShell в виде таблицы.

# Используйте Get-WinEvent для доступа к свойствам каждого зарегистрированного экземпляра события с идентификатором 4625
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## Создайте числовое значение для строки "карты"
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## Начните обработку каждого объекта в массиве $events
$events | ForEach-Object {
    ## Найдите числовое значение в хэш-таблице
    $logonType = $logonTypes[$_.properties[10].value] 
    # Создайте настраиваемый объект PowerShell для вывода соответствующих свойств события
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Format-Table -Wrap

На этом этапе у вас теперь есть сценарий, который возвращает объекты типа PSCustomObject, позволяя вам выполнять множество различных видов анализа! Для завершения анализа этого учебника приоритезируйте попытки сбоя аутентификации по TargetUserName. Чтобы упорядочить сбои по свойству TargetUserName, объедините вышеуказанный код с командой Group-Object. Используйте Sort-Object и его переключатель Descending, чтобы выявить наиболее оскорбляющего пользователя.

#Используйте Get-WinEvent для доступа к свойствам каждого зарегистрированного экземпляра события с идентификатором 4625
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## Создайте числовое значение для строки "map"
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## Начните обработку каждого объекта в массиве $events
$events | ForEach-Object {
    ## Найдите числовое значение в хэш-таблице
    $logonType = $logonTypes[$_.properties[10].value] 
    #Создайте пользовательский объект PowerShell для вывода соответствующих свойств события 
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Group-Object -Property TargetUserName | Sort-Object -Property Count -Descending

Отличная работа! Вы только что использовали PowerShell для обнаружения атаки методом грубой силы, которую вы ранее симулировали в этом посте. Согласно выводу, AtaBlogUser не смог прошел аутентификацию 30 раз за последние 24 часа!

AtaBlogUser Logon Failures

Следующие шаги

В этом учебном пособии вы узнали, как Windows регистрирует события, как включить регистрацию событий для определенных типов событий и как создать инструмент PowerShell для запроса этих событий.

С помощью скрипта PowerShell, который у вас есть, как вы можете его улучшить? Как вы возьмете код, который вы узнали сегодня, и создадите лучший инструмент?

Source:
https://adamtheautomator.com/windows-security-events/