четверг, 8 декабря 2016 г.

Windows. Контроль запускаемого ПО

Приветствую, уважаемый читатель!


Недавно читал различные материалы по мониторингу событий безопасности Windows и наткнулся на интересную статью - https://habrahabr.ru/post/202914/. Мне понравилась идея, но реализацию я решил слегка переработать. Учитывая, что пользователи часто являются самым слабым звеном в системе безопасности, контроль  запускаемых на их компьютерах программ бывает очень полезен. Эту тему и рассмотрим сегодня.





Немного опишу алгоритм действий.

1) Включаем аудит нужных нам событий.
2) Из журнала событий безопасности Windows за какой-либо период получаем события запуска нового процесса и события завершения процесса.
3) Упаковываем нужные поля события в json и отправляем на Splunk.
4) Проводим различные операции с полученной информацией.     


Включить аудит событий создания нового процесса и его завершения для рускоязычной версии Windows можно следующими командами (спасибо хабр):

auditpol.exe /set/category:"Подробное отслеживание"/subcategory:"Создание процесса"/success:enable/failure:enable

auditpol.exe /set /category:"Подробное отслеживание" /subcategory:"Завершение процесса" /success:enable /failure:enable

Для получения событий будем использовать powershell и его командлет Get-EventLog. Текст скрипта и пояснение некоторых моментов ниже.  

$host_name = $env:COMPUTERNAME
$events = Get-EventLog -LogName Security -instanceID 4688,4689 -Newest 1000 | select EventID,MachineName,Message,TimeGenerated

$events | foreach {

        "`n New Event*********************************************** `n"
        $EventID = $_.EventID
       
        if ($EventID -eq 4688) {
            $message = $_.Message.split("`n").replace("`t","")
            $time = $_.TimeGenerated.toString()
            $intNum = ($message | Select-String -pattern "ИД нового процесса").ToString().Replace("ИД нового процесса:","").Replace("`r","")
 | ConvertTo-Json
            $ProcName = ($message | Select-String -pattern "Имя нового процесса").ToString().Replace("Имя нового процесса:","").Replace("`r","")
 | ConvertTo-Json
       
        $JSONDoc = @"
{
"host": "http_host", 
"index": "main",
"sourcetype": "ProcStart",
"event": {
"EventID": "$EventID",
"GenTime": "$time",
"Hostname": "$host_name",
"ProcID": $intNum,
"ProcName": $ProcName
}
}
"@

        $JSONDoc
        Invoke-WebRequest -uri "http://<splunkip>:8088/services/collector" -Headers @{"Authorization"="Splunk D3E1D511-0BFC-4ACF-AEE1-B7879E581BA2"} -Method POST -Body $JSONDoc
                }

        if ($EventID -eq 4689) {
            $Endmessage = $_.Message.split("`n").replace("`t","")
            $time = $_.TimeGenerated.toString()
            $intNum = ($Endmessage | Select-String -pattern "Идентификатор процесса:").ToString().Replace("Идентификатор процесса:","").Replace("`r","")
 | ConvertTo-Json
            $ProcName = ($Endmessage | Select-String -pattern "Имя процесса:").ToString().Replace("Имя процесса:","").Replace("`r","")
 | ConvertTo-Json
               
        $JSONDoc = @"
{
"host": "http_host", 
"index": "main",
"sourcetype": "ProcEnd",
"event": {
"EventID": "$EventID",
"GenTime": "$time",
"Hostname": "$host_name",
"ProcID": $intNum,
"ProcName": $ProcName
}
}
"@
                    $JSONDoc
                    Invoke-WebRequest -uri "http://<splunkip>:8088/services/collector" -Headers @{"Authorization"="Splunk D3E1D511-0BFC-4ACF-AEE1-B7879E581BA2"} -Method POST -Body $JSONDoc
}
}


Пояснение:

1) Получаем события запуска нового процесса(4688) и завершения процесса(4689) из журнала безопасности. Для примера берем 1000 новых событий.

Get-EventLog -LogName Security -instanceID 4688,4689 -Newest 1000

2) Для удобства избавляемся от ненужных специальных символов в тексте события.

$message = $_.Message.split("`n").replace("`t","")

3) Из текста события получаем нужные строки и переводим их в json-формат.  

$intNum = ($message | Select-String -pattern "ИД нового процесса").ToString().Replace("ИД нового процесса:","").Replace("`r","")   |  ConvertTo-Json

$ProcName = ($message | Select-String -pattern "Имя нового процесса").ToString().Replace("Имя нового процесса:","").Replace("`r","")  | ConvertTo-Json

  
4) Отправляем POST-запрос с событием на Splunk-сервер. В качестве Authorization-заголовка добавляем токен.    

Invoke-WebRequest -uri "http://<splunkip>:8088/services/collector" -Headers @{"Authorization"="Splunk D3E1D511-0BFC-4ACF-AEE1-B7879E581BA2"} -Method POST -Body $JSONDoc


Все события, отправляемые на  Splunk-сервер, разделены на 2 sourcetype. В один складываются события запуска процесса (ProcStart), а в другой события завершения процесса (ProcEnd). Сделано это для того, чтобы взаимосвязь событий между собой реализовать средствами Splunk, а не powershell, т.к. Splunk изначально для этого и придуман.

Теперь переходим к Splunk. Для начала выведем список всех процессов, запущенных на компьютере, с указанием времени выполнения. Вбиваем следующий запрос:

sourcetype=ProcEnd
| eval EndTime = GenTime
| join type=inner ProcID [search sourcetype=ProcStart
| eval StartTime = GenTime
| table ProcID,StartTime]
| eval St = round(strptime(EndTime,"%d.%m.%Y %H:%M:%S")-strptime(StartTime,"%d.%m.%Y %H:%M:%S"),0)
| eval Duration = strftime(St,"%M:%S")

| table ProcID,StartTime,EndTime,Duration,ProcName 

Результат запроса ниже:



Данный запрос соединяет между собой события из 2-х sourcetype по ключевому полю ProcID, в котором хранится значение идентификатора запущенного или завершённого процесса. Дополнительно вычисляется время выполнения конкретного процесса и указывается в отдельном поле «Duration».   

Наиболее интересным является следующая часть запроса:

| eval St = round(strptime(EndTime,"%d.%m.%Y %H:%M:%S")-strptime(StartTime,"%d.%m.%Y %H:%M:%S"),0)
| eval Duration = strftime(St,"%M:%S")

Оператор strptime позволяет перевести время из текущего формата в unix epoch time (UET), а оператор strftime позволяет выполнить обратную манипуляцию. Перевод времени в UET позволяет выполнять математические операции.    

Теперь построим круговую диаграмму для 7 наиболее активно используемых программ. Запрос и результат ниже.

sourcetype=ProcEnd
| eval EndTime = GenTime
| join type=inner ProcID [search sourcetype=ProcStart
| eval StartTime = GenTime
| table ProcID,StartTime]
| eval St = round(strptime(EndTime,"%d.%m.%Y %H:%M:%S")-strptime(StartTime,"%d.%m.%Y %H:%M:%S"),0)
| stats sum(St) as AllTime by ProcName
| sort -AllTime
| head 7



Немного усложним задачу. Предположим, мы заведомо не хотим знать об активности той или иной программы на компьютере пользователя, например, активность системного процесса. Для этого создадим в директории “/opt/splunk/var/run/splunk/csv” файл Process.csv, например, следующего содержания:

Proc
"C:\Windows\System32\wbem\WmiPrvSE.exe"
"C:\Windows\System32\SearchProtocolHost.exe"


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

sourcetype=ProcEnd
| eval EndTime = GenTime
| join type=inner ProcID [search sourcetype=ProcStart
| eval StartTime = GenTime
| table ProcID,StartTime]
| eval St = round(strptime(EndTime,"%d.%m.%Y %H:%M:%S")-strptime(StartTime,"%d.%m.%Y %H:%M:%S"),0)
| search NOT [| inputcsv Process | table ProcName]
| stats sum(St) as AllTime by ProcName
| sort -AllTime
| head 7


Как видим ситуация изменилась J

Собственно вот такой механизм контроля активности ПО.


Комментариев нет:

Отправить комментарий