Несколько месяцев тому назад я приступил к решению одной задачи. Я решил доказать, что PowerShell может использоваться как инструмент контроля безопасности. Я закончил работу над своей публикацией, в которой описывается код PowerShell, позволяющий собирать события файловой системы, выполнять некоторые базовые функции анализа, а затем выводить результаты в графическом формате. Возможно, моя платформа безопасности с использованием скриптов (Security Scripting Platform; SSP) не является минимально жизнеспособным продуктом, но она, как мне кажется, полезна в качестве простого инструмента контроля для одиночного каталога файлов.
По завершении проекта я понимал, что определенный функционал можно усовершенствовать. Обработка событий выполнялась неэф-фективно. Передача информации между различными частями платформы SSP требовала оптимизации, а информация, отображаемая с помощью примитивного кода Out-GridView, была представлена в виде прославленной таблицы.
Я решил повысить жизнеспособность платформы SSP. В первую очередь нужно было оптимизировать процедуру обработки событий. Изначально она была разработана таким образом, что обработчик в моем блоке скрипта Register-EngineEvent (см. информацию о блоках скриптов) извлекал сообщения о событиях файла и отправлял их во внутреннюю очередь, а затем — в основной фрагмент кода, ПО для классификации.
Подумав немного, я понял, что можно отправлять сообщения напрямую с помощью функции Register-EngineEvent -forward из блока скрипта обработки событий и просто удалить ненужный уровень этих жутких очередей.
Ниже представлена упрощенная и оптимизированная версия.
Затем я взял основной фрагмент кода, где выполняется классификация файлов по наличию номеров социального страхования и прочих важных ключевых слов. При поступлении событий из обработчика запускается реклассификация файлов. Затем этот код периодически отображает некоторые результаты классификации.
В последней версии я удалил классификацию в «реальном времени» и сосредоточился на очистке кода PowerShell и улучшении графики — об этом речь пойдет ниже.
В первоначальной версии я выбрал неправильный путь и доверил модулю блокировки данных PowerShell синхронизацию доступа к данным от параллельных задач, которые я применял для выполнения рутинной работы. Последующее тестирование показало, что бесплатный модуль, который реализует командлет Lock-Object, не работает.
Даже начинающие системные программисты знают, что синхронизацию проще выполнять с помощью сообщений, а не низкоуровневых блокировок. Я изменил код, и теперь, как упоминалось выше, сообщения направляются из обработчика событий непосредственно в основной цикл обработки сообщений. Иными словами: мне удалось обеспечивать обработку асинхронных событий в синхронном режиме.
?
Самое заметное мое достижение за последний месяц — я разобрался, как встраивать диаграммы в стиле Майкрософт в PowerShell. Другими словами, гистограммами, линейными, точечными и иными диаграммами, доступными в Excel и Word, можно управлять на программном уровне в PowerShell. Я сравнительно недавно занимаюсь программированием в PowerShell, поэтому меня это сильно порадовало. Дополнительную информацию об элементах управления .Net Framework см. в этой публикации.
Это классно! Поначалу я даже подумал, что смогу также заменить запутанный код Out-GridView.
Но вскоре стало ясно, что проблема состоит в том, что помимо этого приходится иметь дело с элементами интерактивного программи-рования, связанными с формами Майкрософт. Я же просто хотел отображать свои диаграммы .Net и не писать код для низкоуровневых функций. Существует ли упрощенный способ решения этой задачи?
После активных размышлений я пришел к выводу, что простейшим способом в данной ситуации будет запуск каждой диаграммы в ее собственной функции runspace как отдельной задачи. (Примечание для фанатов: таким образом я избавился от необходимости создания функции обработки сообщений для всех диаграмм, так как каждая из них выполняется отдельно в виде модальных диалогов.)
В этом мне также помог бесплатный модуль PowerShell, который сворачивает запутанные элементы управления диаграмм .Net. Спасибо тебе, Мариус!
Ранее я уже настроил систему управления задачами, чтобы сканировать и классифицировать каждый контролируемый файл в каталоге. И теперь для запуска диаграмм мне нужно было просто обеспечить повторное использование этого кода управления задачами.
Я создал круговую диаграмму для представления относительной концентрации конфиденциальных данных, гистограмму для разбивки файлов по типу конфиденциальных данных. Но больше всего я горжусь классической ступенчатой диаграммой событий для условий всплеска доступа к файлам, что может быть признаком атаки.
Моя отличная информационная панель. Неплохо для PowerShell
с диаграммами .Net.
Если кому-то из вас интересен основной фрагмент кода, выполняющего всю работу в моей платформе SSP, то он приведен здесь ниже:
Конечно, в рамках любой задачи главным является не сама цель, а процесс поиска решения. Согласны? В данном случае я узнал главную для себя вещь — PowerShell можно использовать для контроля безопасности. Для одиночного каталога, в небольшой системе. Причем только в случае эпизодического использования.
Я планирую внести определенные улучшения в реализацию, которую я только что представил (добавить графику в режиме реального времени), однако я вовсе не ожидаю, что мое финальное программное обеспече-ние станет чем-то большим, чем просто модельным проектом.
Контроль событий файлов, анализ и графическое отображение информации для всей системы — это крайне сложная задача для одного человека. В принципе, мое решение можно перекодировать, используя C++, но в рамках приложения по-прежнему придется решать проблему задержек и отклонений при обработке низкоуровневых событий. Чтобы сделать это правильно, необходимо иметь некие механизмы глубоко в самой ОС (для начала), а затем выполнять гораздо более серьезный анализ событий файлов, чем тот, что выполняется моим примитивным кодом. Это далеко не просто!
Обычно я заканчиваю подобные публикации категории «сделай сам» словами «вы знаете, о чем речь». Не буду вас разочаровывать.
Вы знаете, о чем речь. Наше собственное решение корпоративного класса является настоящейплатформой безопасности данных (Data Security Platform; DSP), так как оно выполняет функции классификации, анализа, обнаружения угроз и многое другое на уровне целых ИТ-систем.
Не отступайте, пробуйте свои варианты. Может быть, даже на основе этого проекта. Разбирайтесь с реальными возможностями платформы DSP, изучайте ее слабые и сильные стороны.
Есть вопросы? Не стесняйтесь и задавайте их нам!
По завершении проекта я понимал, что определенный функционал можно усовершенствовать. Обработка событий выполнялась неэф-фективно. Передача информации между различными частями платформы SSP требовала оптимизации, а информация, отображаемая с помощью примитивного кода Out-GridView, была представлена в виде прославленной таблицы.
Новые и улучшенные возможности
Я решил повысить жизнеспособность платформы SSP. В первую очередь нужно было оптимизировать процедуру обработки событий. Изначально она была разработана таким образом, что обработчик в моем блоке скрипта Register-EngineEvent (см. информацию о блоках скриптов) извлекал сообщения о событиях файла и отправлял их во внутреннюю очередь, а затем — в основной фрагмент кода, ПО для классификации.
Подумав немного, я понял, что можно отправлять сообщения напрямую с помощью функции Register-EngineEvent -forward из блока скрипта обработки событий и просто удалить ненужный уровень этих жутких очередей.
Ниже представлена упрощенная и оптимизированная версия.
1. #Count events, detect bursts, forward to main interface
2.
3. $cur = Get-Date
4. $Global:Count=0
5. $Global:baseline = @{"Monday" = @(1,1,1); "Tuesday" = @(1,.5,1);"Wednesday" = @(4,4,4);"Thursday" = @(7,12,4); "Friday" = @(5,4,6); "Saturday"=@(2,1,1); "Sunday"= @(2,4,2)}
6. $Global:cnts = @(0,0,0)
7. $Global:burst = $false
8. $Global:evarray = New-Object System.Collections.ArrayList
9.
10. $action = {
11. $Global:Count++
12. $d=(Get-Date).DayofWeek
13. $i= [math]::floor((Get-Date).Hour/8)
14.
15. $Global:cnts[$i]++
16.
17.
18. #event auditing!
19.
20. $rawtime = $EventArgs.NewEvent.TargetInstance.LastAccessed.Substring(8,6)
21. $filename = $EventArgs.NewEvent.TargetInstance.Name
22. $etime= [datetime]::ParseExact($rawtime,"HHmmss",$null)
23.
24.
25. $msg="$($etime)): Access of file $($filename)"
26. $msg|Out-File C:\Users\Administrator\Documents\events.log -Append
27.
28. New-Event -SourceIdentifier Delta -MessageData "Access" -EventArguments $filename #notify
29.
30. $Global:evarray.Add(@($filename,$etime))
31. if(!$Global:burst) {
32. $Global:start=$etime
33. $Global:burst=$true
34. }
35. else {
36. if($Global:start.AddMinutes(15) -gt $etime ) {
37. $Global:Count++
38. #File behavior analytics
39. $sfactor=2*[math]::sqrt( $Global:baseline["$($d)"][$i])
40.
41. if ($Global:Count -gt $Global:baseline["$($d)"][$i] + 2*$sfactor) { #at 95% level of poisson
42.
43.
44. "$($etime): Burst of $($Global:Count) accesses"| Out-File C:\Users\Administrator\Documents\events.log -Append
45. $Global:Count=0
46. $Global:burst =$false
47. New-Event -SourceIdentifier Delta -MessageData "Burst" -EventArguments $Global:evarray #notify on burst
48.
49. $Global:evarray= [System.Collections.ArrayList] @()
50. }
51. }
52. else { $Global:burst =$false; $Global:Count=0; $Global:evarray= [System.Collections.ArrayList] @()}
53. }
54. }
55.
56. Register-EngineEvent -SourceIdentifier Delta -Forward
57. Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'CIM_DataFile' and TargetInstance.Path = '\\Users\\Administrator\\' and targetInstance.Drive = 'C:' and (targetInstance.Extension = 'txt' or targetInstance.Extension = 'doc' or targetInstance.Extension = 'rtf') and targetInstance.LastAccessed > '$($cur)' " -sourceIdentifier "Accessor" -Action $action
58. Write-Host "starting engine ..."
59.
60. while ($true) {
61.
62. Wait-Event -SourceIdentifier Access # just hang on this so I don't exit
63.
64. }
Затем я взял основной фрагмент кода, где выполняется классификация файлов по наличию номеров социального страхования и прочих важных ключевых слов. При поступлении событий из обработчика запускается реклассификация файлов. Затем этот код периодически отображает некоторые результаты классификации.
В последней версии я удалил классификацию в «реальном времени» и сосредоточился на очистке кода PowerShell и улучшении графики — об этом речь пойдет ниже.
В первоначальной версии я выбрал неправильный путь и доверил модулю блокировки данных PowerShell синхронизацию доступа к данным от параллельных задач, которые я применял для выполнения рутинной работы. Последующее тестирование показало, что бесплатный модуль, который реализует командлет Lock-Object, не работает.
Даже начинающие системные программисты знают, что синхронизацию проще выполнять с помощью сообщений, а не низкоуровневых блокировок. Я изменил код, и теперь, как упоминалось выше, сообщения направляются из обработчика событий непосредственно в основной цикл обработки сообщений. Иными словами: мне удалось обеспечивать обработку асинхронных событий в синхронном режиме.
?
PowerShell и диаграммы .Net Framework
Самое заметное мое достижение за последний месяц — я разобрался, как встраивать диаграммы в стиле Майкрософт в PowerShell. Другими словами, гистограммами, линейными, точечными и иными диаграммами, доступными в Excel и Word, можно управлять на программном уровне в PowerShell. Я сравнительно недавно занимаюсь программированием в PowerShell, поэтому меня это сильно порадовало. Дополнительную информацию об элементах управления .Net Framework см. в этой публикации.
Это классно! Поначалу я даже подумал, что смогу также заменить запутанный код Out-GridView.
Но вскоре стало ясно, что проблема состоит в том, что помимо этого приходится иметь дело с элементами интерактивного программи-рования, связанными с формами Майкрософт. Я же просто хотел отображать свои диаграммы .Net и не писать код для низкоуровневых функций. Существует ли упрощенный способ решения этой задачи?
После активных размышлений я пришел к выводу, что простейшим способом в данной ситуации будет запуск каждой диаграммы в ее собственной функции runspace как отдельной задачи. (Примечание для фанатов: таким образом я избавился от необходимости создания функции обработки сообщений для всех диаграмм, так как каждая из них выполняется отдельно в виде модальных диалогов.)
В этом мне также помог бесплатный модуль PowerShell, который сворачивает запутанные элементы управления диаграмм .Net. Спасибо тебе, Мариус!
Ранее я уже настроил систему управления задачами, чтобы сканировать и классифицировать каждый контролируемый файл в каталоге. И теперь для запуска диаграмм мне нужно было просто обеспечить повторное использование этого кода управления задачами.
Я создал круговую диаграмму для представления относительной концентрации конфиденциальных данных, гистограмму для разбивки файлов по типу конфиденциальных данных. Но больше всего я горжусь классической ступенчатой диаграммой событий для условий всплеска доступа к файлам, что может быть признаком атаки.
Моя отличная информационная панель. Неплохо для PowerShell
с диаграммами .Net.
Если кому-то из вас интересен основной фрагмент кода, выполняющего всю работу в моей платформе SSP, то он приведен здесь ниже:
1. $scan = { #file content scanner
2. $name=$args[0]
3. function scan {
4. Param (
5. [parameter(position=1)]
6. [string] $Name
7. )
8. $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}' }
9.
10. $data = Get-Content $Name
11.
12. $cnts= @()
13.
14. if($data.Length -eq 0) { return $cnts}
15.
16. foreach ($key in $classify.Keys) {
17.
18. $m=$classify[$key].matches($data)
19.
20. if($m.Count -gt 0) {
21. $cnts+= @($key,$m.Count)
22. }
23. }
24. $cnts
25. }
26. scan $name
27. }
28.
29.
30.
31.
32. #launch a .net chart
33. function nchart ($r, $d, $t,$g,$a) {
34.
35. $task= {
36. Param($d,$t,$g,$a)
37.
38. Import-Module C:\Users\Administrator\Documents\charts.psm1
39. $chart = New-Chart -Dataset $d -Title $t -Type $g -Axis $a
40. Show-Chart $chart
41.
42. }
43. $Task = [powershell]::Create().AddScript($task).AddArgument($d).AddArgument($t).AddArgument($g).AddArgument($a)
44. $Task.RunspacePool = $r
45. $Task.BeginInvoke()
46.
47. }
48.
49. Register-EngineEvent -SourceIdentifier Delta -Action {
50.
51. if($event.MessageData -eq "Burst") { #just look at bursts
52. New-Event -SourceIdentifier File -MessageData $event.MessageData -EventArguments $event.SourceArgs
53. }
54.
55.
56. Remove-Event -SourceIdentifier Delta
57. }
58.
59.
60.
61.
62. $list=Get-WmiObject -Query "SELECT * From CIM_DataFile where Path = '\\Users\\Administrator\\' and Drive = 'C:' and (Extension = 'txt' or Extension = 'doc' or Extension = 'rtf')"
63.
64.
65. #long list --let's multithread
66.
67. #runspace
68. $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1,5)
69. $RunspacePool.Open()
70. $Tasks = @()
71.
72.
73.
74.
75. foreach ($item in $list) {
76.
77. $Task = [powershell]::Create().AddScript($scan).AddArgument($item.Name)
78. $Task.RunspacePool = $RunspacePool
79.
80. $status= $Task.BeginInvoke()
81. $Tasks += @($status,$Task,$item.Name)
82. }
83.
84.
85.
86.
87. #wait
88. while ($Tasks.isCompleted -contains $false){
89.
90. }
91.
92.
93. #Analytics, count number of sensitive content for each file
94. $obj = @{}
95. $tdcnt=0
96. $sfcnt=0
97. $nfcnt=0
98.
99.
100. for ($i=0; $i -lt $Tasks.Count; $i=$i+3) {
101. $match=$Tasks[$i+1].EndInvoke($Tasks[$i])
102.
103. if ($match.Count -gt 0) {
104. $s = ([string]$Tasks[$i+2]).LastIndexOf("\")+1
105.
106. $obj.Add($Tasks[$i+2].Substring($s),$match)
107. for( $j=0; $j -lt $match.Count; $j=$j+2) {
108. switch -wildcard ($match[$j]) {
109. 'Top*' { $tdcnt+= 1 }
110.
111. 'Sens*' { $sfcnt+= 1}
112.
113. 'Numb*' { $nfcnt+=1}
114.
115. }
116.
117. }
118. }
119. $Tasks[$i+1].Dispose()
120.
121. }
122.
123.
124. #Display Initial Dashboard
125. #Pie chart of sensitive files based on total counts of senstive dat
126. $piedata= @{}
127. foreach ( $key in $obj.Keys) {
128. $senscnt =0
129. for($k=1; $k -lt $obj[$key].Count;$k=$k+2) {
130. $senscnt+= $obj[$key][$k]
131.
132. }
133. $piedata.Add($key, $senscnt)
134.
135. }
136.
137.
138. nchart $RunspacePool $piedata "Files with Sensitive Content" "Pie" $false
139.
140. #Bar Chart of Total Files, Sensitive vs Total
141. $bardata = @{"Total Files" = $Tasks.Count}
142. $bardata.Add("Files w. Top Secret",$tdcnt)
143. $bardata.Add("Files w. Sensitive", $sfcnt)
144. $bardata.Add("Files w. SS Numbers",$nfcnt)
145.
146.
147. nchart $RunspacePool $bardata "Sensitive Files" "Bar" $false
148.
149.
150. #run event handler as a seperate job
151. Start-Job -Name EventHandler -ScriptBlock({C:\Users\Administrator\Documents\evhandler.ps1})
152.
153.
154. while ($true) { #main message handling loop
155.
156. [System.Management.Automation.PSEventArgs] $args = Wait-Event -SourceIdentifier File # wait on event
157. Remove-Event -SourceIdentifier File
158. #Write-Host $args.SourceArgs
159. if ($args.MessageData -eq "Burst") {
160. #Display Bursty event
161. $dt=$args.SourceArgs
162. #time in seconds
163. [datetime]$sevent =$dt[0][1]
164.
165. $xyarray = [ordered]@{}
166. $xyarray.Add(0,1)
167. for($j=1;$j -lt $dt.Count;$j=$j+1) {
168. [timespan]$diff = $dt[$j][1] - $sevent
169. $xyarray.Add($diff.Seconds,$j+1)
170. }
171. nchart $RunspacePool $xyarray "Burst Event" "StepLine" $true
172. }
173.
174.
175. }#while
176.
177. Write-Host "Done!"
Извлеченные уроки
Конечно, в рамках любой задачи главным является не сама цель, а процесс поиска решения. Согласны? В данном случае я узнал главную для себя вещь — PowerShell можно использовать для контроля безопасности. Для одиночного каталога, в небольшой системе. Причем только в случае эпизодического использования.
Я планирую внести определенные улучшения в реализацию, которую я только что представил (добавить графику в режиме реального времени), однако я вовсе не ожидаю, что мое финальное программное обеспече-ние станет чем-то большим, чем просто модельным проектом.
Контроль событий файлов, анализ и графическое отображение информации для всей системы — это крайне сложная задача для одного человека. В принципе, мое решение можно перекодировать, используя C++, но в рамках приложения по-прежнему придется решать проблему задержек и отклонений при обработке низкоуровневых событий. Чтобы сделать это правильно, необходимо иметь некие механизмы глубоко в самой ОС (для начала), а затем выполнять гораздо более серьезный анализ событий файлов, чем тот, что выполняется моим примитивным кодом. Это далеко не просто!
Обычно я заканчиваю подобные публикации категории «сделай сам» словами «вы знаете, о чем речь». Не буду вас разочаровывать.
Вы знаете, о чем речь. Наше собственное решение корпоративного класса является настоящейплатформой безопасности данных (Data Security Platform; DSP), так как оно выполняет функции классификации, анализа, обнаружения угроз и многое другое на уровне целых ИТ-систем.
Не отступайте, пробуйте свои варианты. Может быть, даже на основе этого проекта. Разбирайтесь с реальными возможностями платформы DSP, изучайте ее слабые и сильные стороны.
Есть вопросы? Не стесняйтесь и задавайте их нам!