ITセキュリティ用のPowerShellアプリケーション。 パートV:スクリプトセキュリティプラットフォームの最適化

数ヶ月前、私は1つの問題を解決し始めました。 PowerShellをセキュリティ制御ツールとして使用できることを証明することにしました。 ファイルシステムイベントを収集し、いくつかの基本的な分析機能を実行し、結果をグラフ形式で表示できるPowerShellコードについて説明している出版物の作業を終了しました。 私のセキュリティスクリプティングプラットフォーム(SSP)は、実行可能性が最も低い製品ではないかもしれませんが、単一のファイルディレクトリの単純な制御ツールとして役立つように思えます。



プロジェクトが完了すると、特定の機能を改善できることに気付きました。 イベント処理は非効率的でした。 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チャート



この1か月で最も注目すべき成果は、PowerShellにMicrosoftスタイルの図を埋め込む方法を見つけたことです。 つまり、ExcelおよびWordで使用可能な棒グラフ、折れ線グラフ、散布図、およびその他のグラフは、PowerShellでプログラムで制御できます。 私は比較的最近PowerShellでプログラミングをしているので、とても嬉しかったです。 .Net Frameworkコントロールの詳細については、この資料を参照してください。



これはすごい! 最初は、紛らわしいOut-GridViewコードも置き換えることができると考えていました。

しかし、問題はこれに加えて、Microsoftフォームに関連するインタラクティブプログラミング要素を処理しなければならないことがすぐに明らかになりました。 低レベルの関数のコードを書くのではなく、.Netダイアグラムを表示したかっただけです。 この問題を解決する簡単な方法はありますか?



積極的に検討した結果、この状況で最も簡単な方法は、各ダイアグラムを独自のランスペース関数で個別のタスクとして実行することになるという結論に達しました。 (ファンへの注意:この方法では、すべてのダイアグラムがモーダルダイアログの形式で個別に実行されるため、すべてのダイアグラムに対してメッセージ処理関数を作成する必要がなくなりました。)



複雑な.Netチャートコントロールを折りたたむ無料のPowerShellモジュールも、この点で役立ちました。 ありがとうマリウス!



前に、ディレクトリ内の各制御ファイルをスキャンして分類するタスク管理システムをすでにセットアップしました。 そして今、チャートを実行するには、このタスク管理コードが再利用されたことを確認する必要がありました。



機密データの相対的な集中度を表す円グラフ、機密データの種類ごとにファイルを分類するヒストグラムを作成しました。 しかし何よりも、ファイルへのアクセスのバーストの状態に関するイベントの古典的な段階的な図を誇りに思っています。これは攻撃の兆候である可能性があります。







私の素晴らしいダッシュボード。 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 ++を使用して再コーディングできますが、アプリケーションの一部として、低レベルのイベントを処理する際の遅延と偏差の問題を解決する必要があります。 これを正しく行うには、OS自体の奥深くにいくつかのメカニズムがあり(スターター用)、プリミティブコードによって実行されるものよりもはるかに深刻なファイルイベントの分析を実行する必要があります。 これは決して簡単ではありません!



通常、私はそのような日曜大工の出版物を「あなたはそれが何であるかを知っている」という言葉で終わらせます。 失望させません。



あなたはそれが何であるか知っています。 自社のエンタープライズクラスのソリューションは、真のデータセキュリティプラットフォーム(DSP)であり、分類、分析、脅威検出などの機能をITシステム全体のレベルで実行します。



後退しないで、オプションを試してください。 このプロジェクトに基づいているかもしれません。 DSPプラットフォームの実際の機能を理解し、その弱点と強みを探ります。



質問がありますか? お気軽にお問い合わせください!



All Articles