PowerShell для ИТ-безопасности. Часть IV: платформа безопасности с использованием скриптов

в 14:34, , рубрики: big data, powershell, Varonis, Блог компании Varonis Systems, информационная безопасность, хранение данных

PowerShell для ИТ-безопасности. Часть IV: платформа безопасности с использованием скриптов - 1

В предыдущей заметке этой серии я предложил возможность объединения моих отдельных скриптов — один для обработки событий, другой для классификации — в одну систему. Не замахнуться ли на платформу безопасности на основе одного кода PowerShell?

Проработав некоторые детали, в основном относящиеся к зубодробительным событиям PowerShell, я смог заявить о своей победе и зарегистрировал патент на платформу безопасности на базе скриптов — SSP (Security Scripting Platform ).

Соединенные штаты PowerShell

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

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

1.	Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'CIM_DataFile' and TargetInstance.Path = '\Users\bob\' and targetInstance.Drive = 'C:' and (targetInstance.Extension = 'doc' or targetInstance.Extension = 'txt)' and targetInstance.LastAccessed > '$($cur)' " -sourceIdentifier "Accessor" -Action $action

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

Это упрощенная версия технологии анализа поведения пользователей, которая широко применяется нами здесь в компании Varonis.

Пока все идет хорошо.

Затем в третьей заметке я показал, как с помощью PowerShell можно относительно просто просканировать и классифицировать файлы в папке. Поскольку это действие связано с интенсивным использованием диска, для ускорения классификации имеет смысл использовать функцию многозадачности PowerShell, известную как Runspaces.

В существующих решениях по обработке событий файлов и классификации данных, скажем Data Classification Framework компании Varonis, используется более оптимизированный подход к распределению файлов по категориям путем передачи операций с файлами в модуль классификации.

Почему?

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

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

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

В основном это классическая комбинация внутреннего модуля и внешнего интерфейса.
Вопрос состоит в том, как соединить два скрипта: как сообщить классификатору о произошедшей операции с файлом?

Сообщения и события

После того, как я провел несколько долгих дней за изучением форумов разработчиков, я наконец наткнулся на функцию PowerShell под именем Register-EngineEvent.

Что представляет собой этот командлет PowerShell?

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

Дело в том, что у register-EngineEvent есть два варианта работы. С параметром -forward этот командлет работает как издатель событий. Без параметра -forward он выполняет роль получателя.

Понятно?

Я использовал событие с именем Delta — которое технически выполняет роль значения идентификатора SourceIdentifer — для координации работы моего скрипта обработки событий, который выдает сообщения о событиях, и моего скрипта-классификатора, который получает эти сообщения.

В первом из этих двух скриптов, отрывок из которого представлен далее, я показываю, как я регистрировал публичное имя события Delta с помощью строки -Register-EngineEvent -forward, а затем ожидал внутренних событий доступа к файлам. Когда такое событие происходило, я отправлял сообщение о внутреннем событии файла — говоря на языке PowerShell, пересылал его — соответствующему командлету Register-EngineEvent в скрипте-классификаторе во втором отрывке кода.

1.	Register-EngineEvent -SourceIdentifier Delta -Forward
2.	While ($true) {
3.	$args=Wait-Event -SourceIdentifier Access # wait on internal file event
4.	Remove-Event -SourceIdentifier Access
5.	if ($args.MessageData -eq "Access") { 
6.	#do some plain access processing 
7.	New-Event -SourceIdentifier Delta -EventArguments $args.SourceArgs -MessageData $args.MessageData #send event to classifier via forwarding
8.	}
9.	elseif ($args.MessageData -eq "Burst") {
10.	#do some burst processing
11.	New-Event -SourceIdentifier Delta -EventArguments $args.SourceArgs -MessageData $args.MessageData #send event to classifier via forwarding
12.	}
13.	}

На стороне получателя я не использовал параметр -forward и вместо этого переходил в блок скрипта PowerShell, который асинхронно обрабатывал событие. Результат вы можете увидеть ниже.

1.	Register-EngineEvent -SourceIdentifier Delta -Action {
2.	
3.	Remove-Event -SourceIdentifier Delta
4.	if($event.MessageData -eq "Access") {
5.	$filename = $args[0] #got file!
6.	Lock-Object $deltafile.SyncRoot{ $deltafile[$filename]=1} #lock&load 
7.	}
8.	elseif ($event.Messagedata -eq "Burst") {
9.	#do something 
10.	}
11.	
12.	}

Запутались? А я говорил недавно, что обработка событий файлов — это непросто, и что мои учебные скрипты не справятся с обработкой реальных производственных нагрузок?
Путаница возникает, поскольку командлеты New-Event и Wait-Event для внутреннего обмена сообщениями о событиях отличаются от функций внешнего обмена сообщениями о событиях, предоставленных в Register-EngineEvent.

Еще больше путаницы

Полный скрипт классификации представлен далее. Я подробнее расскажу о нем в следующей и последней заметке из этой серии. А пока посмотрите на этот скрипт и обратите внимание на обработку событий и многозадачность.

1.	Import-Module -Name .pslock.psm1 -Verbose
2.	function updatecnts {
3.	Param ( 
4.	[parameter(position=1)] 
5.	$match, 
6.	[parameter(position=2)]
7.	$obj
8.	)
9.	
10.	for($j=0; $j -lt $match.Count;$j=$j+2) { 
11.	switch -wildcard ($match[$j]) {
12.	'Top*' { $obj| Add-Member -Force -type NoteProperty -Name Secret -Value $match[$j+1] }
13.	'Sens*' { $obj| Add-Member -Force -type NoteProperty -Name Sensitive -Value $match[$j+1] }
14.	'Numb*' { $obj| Add-Member -Force -type NoteProperty -Name Numbers -Value $match[$j+1] } 
15.	}
16.	
17.	}
18.	
19.	return $obj
20.	}
21.	
22.	$scan = {
23.	$name=$args[0]
24.	function scan {
25.	Param (
26.	[parameter(position=1)]
27.	[string] $Name
28.	)
29.	$classify =@{"Top Secret"=[regex]'[tT]op [sS]ecret'; "Sensitive"=[regex]'([Cc]onfidential)|([sS]nowflake)'; "Numbers"=[regex]'[0-9]{3}-[0-9]{2}-[0-9]{3}' }
30.	
31.	$data = Get-Content $Name
32.	
33.	$cnts= @()
34.	
35.	if($data.Length -eq 0) { return $cnts} 
36.	
37.	foreach ($key in $classify.Keys) {
38.	
39.	$m=$classify[$key].matches($data) 
40.	
41.	if($m.Count -gt 0) {
42.	$cnts+= @($key,$m.Count) 
43.	}
44.	} 
45.	$cnts 
46.	}
47.	scan $name
48.	}
49.	
50.	
51.	$outarray = @() #where I keep classification stats
52.	$deltafile = [hashtable]::Synchronized(@{}) #hold file events for master loop 
53.	
54.	$list=Get-WmiObject -Query "SELECT * From CIM_DataFile where Path = '\Users\bob\' and Drive = 'C:' and (Extension = 'txt' or Extension = 'doc' or Extension = 'rtf')" 
55.	
56.	
57.	#long list --let's multithread
58.	
59.	#runspace
60.	$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1,5)
61.	$RunspacePool.Open()
62.	$Tasks = @()
63.	
64.	
65.	foreach ($item in $list) {
66.	
67.	$Task = [powershell]::Create().AddScript($scan).AddArgument($item.Name)
68.	$Task.RunspacePool = $RunspacePool
69.	
70.	$status= $Task.BeginInvoke()
71.	$Tasks += @($status,$Task,$item.Name)
72.	}
73.	
74.	
75.	Register-EngineEvent -SourceIdentifier Delta -Action {
76.	
77.	Remove-Event -SourceIdentifier Delta
78.	if($event.MessageData -eq "Access") {
79.	$filename = $args[0] #got file
80.	Lock-Object $deltafile.SyncRoot{ $deltafile[$filename]=1} #lock& load
81.	}
82.	elseif ($event.Messagedata -eq "Burst") {
83.	#do something
84.	}
85.	}
86.	
87.	while ($Tasks.isCompleted -contains $false){
88.	
89.	}
90.	
91.	#check results of tasks
92.	for ($i=0; $i -lt $Tasks.Count; $i=$i+3){
93.	$match=$Tasks[$i+1].EndInvoke($Tasks[$i])
94.	
95.	
96.	if ($match.Count -gt 0) { # update clasafication array 
97.	$obj = New-Object System.Object
98.	$obj | Add-Member -type NoteProperty -Name File -Value $Tasks[$i+2]
99.	#defaults
100.	$obj| Add-Member -type NoteProperty -Name Secret -Value 0
101.	$obj| Add-Member -type NoteProperty -Name Sensitive -Value 0
102.	$obj| Add-Member -type NoteProperty -Name Numbers -Value 0
103.	
104.	$obj=updatecnts $match $obj
105.	$outarray += $obj
106.	} 
107.	$Tasks[$i+1].Dispose()
108.	
109.	}
110.	
111.	$outarray | Out-GridView -Title "Content Classification" #display
112.	
113.	#run event handler as a separate job
114.	Start-Job -Name EventHandler -ScriptBlock({C:UsersbobDocumentsevhandler.ps1}) #run event handler in background
115.	
116.	
117.	while ($true) { #the master executive loop
118.	
119.	
120.	Start-Sleep -seconds 10
121.	Lock-Object $deltafile.SyncRoot { #lock and iterate through synchronized list
122.	foreach ($key in $deltafile.Keys) { 
123.	
124.	$filename=$key
125.	
126.	if($deltafile[$key] -eq 0) { continue} #nothing new
127.	
128.	$deltafile[$key]=0
129.	$match = & $scan $filename #run scriptblock
130.	#incremental part
131.	
132.	$found=$false
133.	$class=$false
134.	if($match.Count -gt 0) 
135.	{$class =$true} #found sensitive data
136.	if($outarray.File -contains $filename) 
137.	{$found = $true} #already in the array 
138.	if (!$found -and !$class){continue}
139.	
140.	#let's add/update
141.	if (!$found) {
142.	
143.	$obj = New-Object System.Object
144.	$obj | Add-Member -type NoteProperty -Name File -Value $Tasks[$i+2]
145.	#defaults
146.	$obj| Add-Member -type NoteProperty -Name Secret -Value 0
147.	$obj| Add-Member -type NoteProperty -Name Sensitive -Value 0
148.	$obj| Add-Member -type NoteProperty -Name Numbers -Value 0
149.	
150.	$obj=updatecnts $match $obj
151.	
152.	}
153.	else {
154.	$outarray|? {$_.File -eq $filename} | % { updatecnts $match $_} 
155.	}
156.	$outarray | Out-GridView -Title "Content Classification ( $(get-date -format M/d/yy:HH:MM) )" 
157.	
158.	} #foreach
159.	
160.	} #lock
161.	}#while
162.	
163.	Write-Host "Done!"

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

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

Это классическая ситуация состязания. И для обработки этой ситуации я решил использовать синхронизированныепеременные PowerShell.

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

Автор: Александра

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js