Текстовая версия выступления на PHD11

Пару слов о проблеме

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

Live response — это область, которая занимается сбором информации с работающего компьютера, чтобы определить, произошел ли инцидент.

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

Существуют различные инструменты для проведения live response: коммерческие, с открытым исходным кодом и встроенные возможности ОС.

Использование opensource и коммерческих инструментов связано с рядом проблем:

  • Утилиты могут отправлять телеметрию разработчику

  • Отсутствие описания анализируемых журналов и EventId

Неудобство фильтрации оснасткой eventvwr.msc

Фильтрация evtx с помощью стандартной оснастки просмотра событий (eventvwr.msc) ограничена в возможностях.

Проблемы:

  • отсутствует возможность вывести информацию в колонках

  • отсутствуют регулярные выражения и поиск подстрок

  • отсутствует группировка

eventvwr.msc
eventvwr.msc

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

Ограничения XPath для фильтрации событий
Ограничения XPath для фильтрации событий

Одним из основных ограничений XPath 1.0 является то, что он не поддерживает поиск по атрибутам. То есть, если вы хотите найти события, связанные с определенным EventID, вы можете воспользоваться элементом EventID, но вы не сможете использовать атрибуты, вложенных элементов для поиска событий, например: TargetUserName.

Пример события в формате XML
Пример события в формате XML

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

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

Как показано выше, узлы «Элемент» могут содержать «Атрибуты», и мы можем использовать подстановочный знак «@» для поиска узлов «Data».

Пример ниже позволяет найти все события из журнала Security c EventID = 4688. Атрибут Path в директиве Query можно опустить. Путь к журналу указывается в в атрибуте Path директивы Select.

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]]</Select>
  </Query>
</QueryList>

В пример ниже добавляем использования логического оператора OR для поиска события с EventID 4688 или 4624.

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688 or EventID=4624]]</Select>
  </Query>
</QueryList>

В следующем примере добавим фильтрацию по разделу XML - EventData. Для объединения двух условий в одном Select используется логический оператор AND. Вторая часть запроса начинается со знака *, который означает что верхний узел может принимать любое значение, далее мы указываем путь к атрибуту значение которого хотим указать в условии EventData -> Data -> @Атрибут="значение".

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]] and 
             *[EventData[Data[@Name="SubjectUserName"]="hacker"]]</Select>
  </Query>
</QueryList>

XPath позволяет искать значение по всем атрибутам, как в примере ниже. Структура указанные выше изменилась до EventData -> Data -> @Атрибут ="значение". Следующим запросам мы найдем все события где в атрибутах фигурировало "C:\Windows\System32\lsass.exe"

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]] and 
*[EventData[Data="C:\Windows\System32\lsass.exe"]]</Select>
  </Query>
</QueryList>

Оператор Suppress позволяет исключить из конечной выборки события, которые подходят под условие в нем. В примере ниже, мы найдем все события 4624, в которых LogonType=5.

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4624]]</Select>
    <Suppress Path="Security">*[EventData[Data[@Name='LogonType']=5]]</Suppress>
  </Query>
</QueryList>

В пределах одного Query мы можем указывать несколько Select-запросов, также есть возможность запрашивать события из разных журналов.

<QueryList>
  <Query Id="0">
    <Select Path="Security">*[System[EventID=4688]]</Select>
    <Select Path="Windows PowerShell">*</Select>
  </Query>
</QueryList>

В одном QueryList может быть несколько Query. Это удобно для логического разбиения запросов и их фильтрации.

<QueryList>
    <Query Id="0" Path="Security">
        <Select Path="Security">*[System[EventID=4688]]</Select>
    </Query>
    <Query Id="1" Path="Microsoft-Windows-Sysmon/Operational">
        <Select Path="Microsoft-Windows-Sysmon/Operational">*</Select>
    </Query>
</QueryList>

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

Возможности CMD

Возможности CMD ограничены использованием двух основных утилит wevtutil и Findstr. wevtutil позволяет работать с параметрами журналов и создавать к ним запросы. Для запросов в wevtutil также используются XPath-запросы.

wevtutil.exe qe Security /q:"*[EventData[Data[@Name='TargetUserName']='User1' and Data[@Name='LogonType']=2]]" /f:text

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

wevtutil.exe qe Security /q:"*[EventData[Data[@Name='LogonType']=11]]" /f:text | findstr "Account Name"

Возможности PowerShell

В Powershell для работы с журналами существуют два командлета Get-EventLog и Get-WinEvent. Мы рассмотри второй командлет так как он считается актуальным.

Основные возможности Get-WinEvent это использование хеш-таблиц и Xpath для фильтрации событий. Для использование хеш-таблиц используется аргумент -FilterHashtable, его можно опустить и строить запрос сразу с @{<выражение>}.

Ограничение при создании FilterHastale
Ограничение при создании FilterHastale

Рассмотрим несколько примеров использования командлета Get-WinEvent и построения конвейеров с ним.

Следующим примером мы выведем 1000 событий из журнала Security.

Get-WinEvent -LogName Security -MaxEvents 1000

Тот же запрос, но используем Format-List для приведения вывода в читаемый.

Get-WinEvent -LogName Secutity -MaxEvents 10 | Format-List

Используем FilterHashtable. Выведем события из журнала Security с EventId 4688.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 100 | Format-List

Для понимания дальнейших фильтров давайте посмотрим как представлено событие в Powershell, для этого выведем одно событие и воспользуемся командлетом Get-Member.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 1 | Get-Member

Свойство Properties - это список, который хранит основные параметры события, которые расположены в секции EventData xml-представления.

После того, как мы научились получать события из определенного журнала и по определенному EventId, давайте посмотрим каким образом мы можем получить интересующие нас данные. Давайте выведем события 4688, и отобразим время создания события и {$_.Properties[5].value}, которое хранит имя запущенного процесса. Номер элемента списка Properties соответствует номеру атрибута в секции EventData xml-представления события.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 100 | 
select timecreated,{$_.Properties[5].value} | Format-List

Powershell позволяет нам создавать группировки, используя командлет Group-Object. Следующим запросом сгруппируем события Sysmon EventId 3 по следующим полям: процесс, адрес получателя, доменное имя получателя, порт получателя.

Get-WinEvent @{LogName="*sysmon*";ID=3}  -MaxEvents 10000 | 
Where-Object {$_.Properties[16].Value -ne 443} | 
Group-Object {$_.Properties[4].Value},{$_.Properties[14].Value}, {$_.Properties[15].Value}, {$_.Properties[16].Value} | 
Select-Object Name, Count | Sort-Object Count -Descending  | Format-List

Для поиска подстрок можем воспользоваться -Match или -Like.

Get-WinEvent @{LogName="*sysmon*";ID=1}  -MaxEvents 1000 | 
Where-Object {$_.Properties[10].Value -Match ".*cmd.exe" }  | 
Select-Object {$_.Properties[10].Value} | 
Format-List

Поиска событий с известным значением атрибута выполняется быстрее при использовании XPath запросов, чем конвейеров Powershell. Например: запрос ниже найдет все события, связанные с пользователем R00t1k\Vadim.

Get-WinEvent -LogName *Sysmon* -FilterXPath "*[EventData[Data[@Name='User']='LAB\vadim']]" | 
Where-Object {$_.Properties[4].Value -Match ".*WINWORD.exe"} | 
Format-List

Poweshell позволяет представить сообщение в виде xml, выполнив следующий код.

$eventlog = Get-WinEvent -FilterHashtable @{LogName="Security";ID=4624} -MaxEvents 1
$xml = [xml]$eventlog.ToXml()
$xml.Event.EventData.Data

Модуль Powershell Convert-EventLogRecord преобразовывает события в структуру данных, которая позволяет обращаться к атрибутам по их имени. Конвейер для фильтрации событий с Convert-EventLogRecord будет выполняться в 2-3 раза дольше, в отличие от ковейера без его использования.

# С использованием Convert-EventLogRecord
Get-WinEvent -FilterHashtable @{LogName="Security";ID=4624} | 
Convert-EventLogRecord | Where-Object LogonType -ne 5 | 
Select TimeCreated, TargetUserName, LogonType

# Без использования Convert-EventLogRecord
Get-WinEvent @{LogName="Security";Id=4624} | 
Where-Object {$_.Properties[8].Value -ne 5} | 
Select TimeCreated, {$_.Properties[5].Value}, {$_.Properties[8].Value}

Используя командлет Out-GridView мы можем вывести события в виде таблицы.

Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} |
    Select-Object TimeCreated, 
@{Name='User'; Expression={$_.Properties[5].Value}}, 
@{Name='LogonType'; Expression={$_.Properties[8].Value}},
@{Name='SrcIp'; Expression={$_.Properties[18].Value}}  |
    Out-GridView

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

 Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624, 4688} -MaxEvents 1000 | Where-Object {$_.Properties[8].Value -ne 5} |
    ForEach-Object {
        if ($_.Id -eq 4624) {
            $Username = $_.Properties[5].Value
            $LogonType = $_.Properties[8].Value
            $LogonProcess = $_.Properties[9].Value
            $IpAddress = $_.Properties[18].Value
        }
        elseif ($_.Id -eq 4688) {
            $SubjectUserName = $_.Properties[1].Value
            $SubjectUserDomain = $_.Properties[2].Value
            $NewProcessName = $_.Properties[5].Value
            $CommandLine= $_.Properties[8].Value
            $ParrentProcessName= $_.Properties[13].Value
        }
        [PSCustomObject]@{
            Time = $_.TimeCreated
            EventID = $_.Id
            Username = $Username
            LogonType = $LogonType
            LogonProcess = $LogonProcess
            IpAddress = $IpAddress
            SubjectUserName = $SubjectUserName
            SubjectUserDomain = $SubjectUserDomain
            NewProcessName = $NewProcessName
            CommandLine = $CommandLine
            ParrentProcessName = $ParrentProcessName
                    }
    } | Out-GridView

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

Комментарии (5)


  1. VikkorMalansohn
    06.06.2023 05:26

    Как все сложно.

    А нельзя ли было упомянуть список "таскают с собой утилиты для удобной фильтрации" и закрыть тему? :)


    1. d3f0x0 Автор
      06.06.2023 05:26

      Нужно же знать мат.часть)

      А список утилит, можно приглядеть тут


      1. VikkorMalansohn
        06.06.2023 05:26

        Спасибо, сэр.


  1. WAR-S
    06.06.2023 05:26

    Добрый день, сталкивался с такой же задачей, необходимы логировать logon/logoff. Подскажите рассматривали ли пересылку выхлопа например в эластик, построение в кибане дашбордов. Если так, то не смотрели ли в сторону fluentd, который под капотом умеет парсить логи журнала евентов, просто на powershell придется запихивать в цикл и пользоваться флагами по типу:
    Get-EventLog -LogName Security -After (Get-Date).AddSeconds(-5)

    | ConvertTo-JSON -Compress | Out-File -Encoding "utf8" .\logs.txt -Append



    1. d3f0x0 Автор
      06.06.2023 05:26
      +1

      Добрый день! fluentd не сталкивался, а в elk с помощью winlogbeat отправлял