📜 ⬆️ ⬇️

Use PowerShell for IT security. Part V: Security Platform Optimization Using Scripts

A few months ago I began to solve one problem. I decided to prove that PowerShell can be used as a security monitoring tool. I finished work on my publication, which describes PowerShell code that allows you to collect file system events, perform some basic analysis functions, and then display the results in graphical format. Perhaps my security platform using scripts (Security Scripting Platform; SSP) is not a minimally viable product, but it seems to me useful as a simple control tool for a single file directory.

At the end of the project, I realized that certain functionality could be improved. Event processing was performed inefficiently. The transfer of information between different parts of the SSP platform required optimization, and the information displayed using the Out-GridView primitive code was presented in the form of an illustrious table.

New and improved features


I decided to increase the viability of the SSP platform. The first step was to optimize the event handling procedure. Initially, it was designed in such a way that the handler in my Register-EngineEvent script block (see information about script blocks) retrieved messages about file events and sent them to an internal queue, and then into the main code fragment, the classification software.

Thinking a little, I realized that you can send messages directly using the Register-EngineEvent -forward function from the event-processing script block and simply remove the unnecessary level of these creepy queues.
')
Below is a simplified and optimized version.

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. } 

Then I took the main code snippet, where the files are classified according to social security numbers and other important keywords. When events arrive from the handler, the files are reclassified. Then this code periodically displays some classification results.

In the latest version, I removed the classification in "real time" and focused on cleaning PowerShell code and improving graphics - this will be discussed below.

In the original version, I chose the wrong path and entrusted the PowerShell data locking module with synchronization of data access from parallel tasks that I used to perform routine work. Subsequent testing revealed that the free module that implements the Lock-Object cmdlet does not work.

Even novice system programmers know that synchronization is easier to do with messages, rather than low-level locks. I changed the code, and now, as mentioned above, the messages are sent from the event handler directly to the main message loop. In other words: I was able to handle asynchronous events in synchronous mode.

PowerShell and .Net Framework diagrams


My most notable achievement in the last month is that I figured out how to embed Microsoft-style charts in PowerShell. In other words, histograms, linear, dot, and other charts available in Excel and Word can be managed at the program level in PowerShell. I am relatively recently engaged in programming in PowerShell, so I was very pleased with it. For more information about the .Net Framework controls, see this publication.

This is cool! At first, I even thought that I could also replace the tangled Out-GridView code.
But it soon became clear that the problem was that in addition to this, we had to deal with interactive programming elements associated with Microsoft forms. I just wanted to display my .Net diagrams and not write code for low-level functions. Is there a simplified way to solve this problem?

After active reflection, I came to the conclusion that the simplest way in this situation would be to launch each diagram in its own runspace function as a separate task. (Note to fans: this way I got rid of the need to create a message handling function for all the diagrams, since each of them is executed separately in the form of modal dialogs.)

This also helped me with the free PowerShell module, which collapses the intricate controls of the .Net diagrams. Thank you, Marius!

I have previously set up a task management system to scan and classify each monitored file in the directory. And now to run the charts, I just had to ensure that this task management code is reused.

I created a pie chart to represent the relative concentration of sensitive data, a histogram for dividing files by type of sensitive data. But most of all I am proud of the classic step diagram of events for the conditions of the surge in access to files, which can be a sign of an attack.



My great dashboard. Not bad for PowerShell
with .Net diagrams.

If any of you are interested in the main piece of code that does all the work in my SSP platform, then it is listed here below:

 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!" 

Lessons learned


Of course, in any task, the main goal is not the goal itself, but the process of finding a solution. Do you agree? In this case, I learned the main thing for myself - PowerShell can be used for security control. For a single directory, in a small system. And only in the case of occasional use.

I plan to make some improvements to the implementation I just introduced (add graphics in real time), but I don’t expect my final software to become anything more than just a model project.

Monitoring file events, analyzing and graphing information for the entire system is an extremely difficult task for one person. In principle, my solution can be recoded using C ++, but the application will still have to solve the problem of delays and deviations in the processing of low-level events. To do this correctly, it is necessary to have some mechanisms deep in the OS itself (to begin with), and then perform a much more serious analysis of file events than the one that is executed by my primitive code. This is far from easy!

I usually end up doing these kind of “do it yourself” publications with the words “you know what it is about”. I will not disappoint you.

You know what it is about. Our own enterprise-class solution is a true Data Security Platform (DSP), as it performs the functions of classifying, analyzing, detecting threats, and much more at the level of entire IT systems.

Do not back down, try your options. Maybe even based on this project. Understand the real capabilities of the DSP platform, learn its strengths and weaknesses.

Have questions? Feel free to ask them to us!

Source: https://habr.com/ru/post/340312/


All Articles