翻譯|使用教程|編輯:莫成敏|2019-09-23 13:58:40.607|閱讀 536 次
概述:?本教程提供了一個解決方案,使用PowerShell和SQL Monitor,可以迅速警告您一系列Windows錯誤、警告和關鍵事件,包括失敗的服務器登錄嘗試,這將伴隨著對承載您的SQL Server實例的Windows Server的強力密碼攻擊。這是上半部分內容~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
SQL Monitor是一個SQL Server監控工具。它可以監控SQL Servers的健康狀況和活動,并通過電子郵件為您發送監測結果和建議。
本教程提供了一個解決方案,使用PowerShell和SQL Monitor,可以迅速警告您一系列Windows錯誤、警告和關鍵事件,包括失敗的服務器登錄嘗試,這將伴隨著對承載您的SQL Server實例的Windows Server的強力密碼攻擊。本文為上半部分內容~
每當聽到由Windows Server主機上的強行密碼攻擊引發的又一次SQL Server漏洞時,標準反應就是在激動中揮舞著雙手,同時解釋了持續不斷地自動檢查服務器日志以獲取警告的必要性。
最后,拿出一個解決方案。使用Get-WinEvent cmdlet,并在散列表的幫助下,使用PowerShell腳本讀取和過濾Windows事件日志數據。將數據保存在SQL Server數據庫中,因此可以在那里進行掃描,并確保有永久的事件記錄。我編寫了一個簡單的SQL Monitor自定義指標,該指標返回最近10分鐘內記錄的Windows事件數。SQL Monitor將按計劃收集此數據,并在發生這些事件時通知我。
有了這樣的解決方案,您將在五分鐘之內收到有關安全日志中的所有錯誤,警告和關鍵事件以及選擇的其他任何日志的警告,并且您將看到大量的失敗的登錄嘗試這將伴隨強力破解密碼攻擊。我希望即使讀者使用其他警報系統,該解決方案仍然對讀者有用,因為大多數任務是相同的。
獲取Windows安全日志事件
Windows安全日志事件很多。其中很多都沒有任何意義,但是有些是監視安全性的瑰寶。有人可能以為,安全事件的級別可以表明其重要性,但事實并非如此。失敗的登錄嘗試,在任何暴力攻擊中都可能發生,被視為“信息”。但是,一般而言,日志錯誤和警告也很有用,并在許多情況下為我節省了時間。
通過PowerShell閱讀Windows事件和經典日志
SQL不適合此任務,因為只能通過讀取SQL Server錯誤日志和SQL Agent日志xp_readerrorlog。您在SSMS中擁有日志文件查看器,可用于讀取經典日志,這對于臨時調查非常有用。有幾種方法可以在PowerShell中獲取此信息,如Laerte Junior的The PoSh DBA – Reading and Filtering Errors中所述。
該Get-WinEventcmdlet可能是從本地服務器上的100多個事件日志獲取信息的,包括經典的最佳工具系統、安全和應用程序日志。它還會讀取由更高版本的Windows事件日志技術生成的事件日志,以及由Windows事件跟蹤生成的最新事件。單個日志可以包含數千個條目。
如果您以Admin用戶身份運行,此cmdlet允許您列出和調查日志并讀取內容。這里有很多信息,過濾是必不可少的,尤其是當您在幾臺服務器上一個接一個地讀取日志時。如果您明智的應用過濾器,Get-WinEvent可以快速工作。在找到搜索模式之前,可能需要進行一些試驗,以使其找到搜索日志的最佳方式。如果您做對了,那就太快了。
Get-WinEvent查詢
有三種指定查詢的方式。您可以使用XPath查詢或結構化XML查詢。對于像我這樣的普通人,有一些簡單的hash表過濾器,它們的工作原理與濺射參數非常相似,只是參數并未全部公開。
有幾種不同的方法來切割這個巨大的披薩事件。您可以通過日志名稱列表、提供程序名稱、關鍵字枚舉值、事件ID、嚴重性級別或從已存檔經典日志的路徑列表中進行選擇。您可以指定時間段的開始和結束,或指定生成錯誤的用戶ID。這種多功能性適合我們。
創建hash表過濾器很簡單。在這里,我們只是在尋找過去24小時內發生的嚴重、嚴重或錯誤級別的可怕“經典”事件。如果需要掃描其他日志,只需將它們添加到列表中。然后,我們簡單地將過濾器作為Get-WinEvents的FilterHashTable參數。
$Search = @{ LogName = 'application', 'security', 'system'; # we search the application, security and system logs Level = 1, 2, 3; # Verbose 5, Informational 4, Warning 3, Error 2, Critical 1, LogAlways 0 # we do events and errors of warning, error and critical levels StartTime = (get-date) - (New-TimeSpan -Days 1) # We go just one day back as we are calling this regularly }; Get-WinEvent -FilterHashTable $Search -MaxEvents 1000 | Select Id, TimeCreated, Level, LevelDisplayName, Message, ProviderName, LogName
雖然這將為您提供基本的警告和錯誤,但不會使您登錄失敗。這些不是警告,而是信息事件。這需要再次搜索我們要監視的任何特定安全事件,但這些事件不被視為警告。
$FailedLogins = @{ LogName = 'security'; ID = 4625; #add any other security events you want that are informational Level = 0; StartTime = (get-date) - (New-TimeSpan -Days 1) } Get-WinEvent -MaxEvents 1000 -FilterHashTable $FailedLogins | Select Id, TimeCreated, level, LevelDisplayName, Message, ProviderName, LogName
我們將在此時停止,但是您可能會看到您感興趣的其他安全事件。我還沒有演示過,但是您可以通過Get-WinEvent對整個hash表進行管道內襯來進行很多快速搜索。您甚至可以在服務器列表上運行搜索。
PowerShell腳本
現在,我們只需要按計劃執行這些查詢,并將結果存儲在SQL Server數據庫中(在我的示例中稱為ServerEvents)。您必須創建數據庫,但是表(名為臨時表EventsStaging和名為的目標表Events)是由計劃的進程創建的。臨時表是使用Write-SqlTableData cmdlet的-force參數自動創建的。
該腳本使用sqlserver提供程序來完成無聊的工作,即將包含事件日志數據的PowerShell對象復制到臨時表中,然后在服務器上執行SQL代碼以創建目標表,并將在其中找到的所有事件添加到該表中。尚未存儲在目標中的臨時表。
您必須在與ServerEvents數據庫相同的服務器上運行腳本。如果您將Get-WinEvent監視事件的服務器指定為參數,則可以遠程運行它。
分配來運行此計劃任務的管理員用戶必須是SQL Server登錄名,該登錄名僅在ServerEvents數據庫上是dbo角色的成員。我們的腳本需要執行常規工作,以獲取此admin用戶的憑據,該憑據以加密形式存儲在Windows用戶配置文件目錄中,該文件的位置通過環境變量來引用$env:USERPROFILE。僅當您希望避免將SQL Server登錄名分配給本地Windows用戶時才需要這樣做。首次運行腳本時,系統會要求您輸入用戶密碼。希望這對任何用戶僅發生一次。
或者,如果您使用Windows身份驗證,則可以為您分配給該任務的用戶提供此登錄名和該數據庫的dbo用戶角色,而您將其$SQLUserName留空。
$SQLUserName = 'PhilFactor' $SQLInstance = 'MyServer' $SQLDatabase = 'ServerEvents' $StagingTableName = 'EventsStaging' $DestinationTableName = 'Events' $Logfile = 'C:\Scripts\GetWindowErrors.log' $Errors = @() "$(get-date): started out getting errors">>$Logfile Import-Module sqlserver -DisableNameChecking ` -ErrorAction silentlycontinue ` -ErrorVariable +Errors #load the SQLPS functionality set-psdebug -strict $ErrorActionPreference = "stop" $SqlEncryptedPasswordFile = ` "$env:USERPROFILE\$($SqlUserName)-$($SQLInstance).txt" # test to see if we know about the password in a secure string stored in the user area if (Test-Path -path $SqlEncryptedPasswordFile -PathType leaf) { #has already got this set for this login so fetch it $Sqlencrypted = Get-Content $SqlEncryptedPasswordFile | ConvertTo-SecureString $SqlCredentials = ` New-Object System.Management.Automation.PsCredential($SqlUserName, $Sqlencrypted) } else #then we have to ask the user for it { #hasn't got this set for this login $SqlCredentials = get-credential -Credential $SqlUserName $SqlCredentials.Password | ConvertFrom-SecureString | Set-Content $SqlEncryptedPasswordFile } "$(get-date): got credentials for $SqlUserName">>$Logfile <# #> $Search = @{ LogName = 'application', 'security', 'system'; # we search the application, security and system logs Level = 1, 2, 3; # we do events and errors of warning, error and critical StartTime = (get-date) - (New-TimeSpan -Days 1) # We go just one day back }; $FailedLogins = @{ LogName = 'security'; ID = 4625; #add any other security events you want that are Level = 0; StartTime = (get-date) - (New-TimeSpan -Days 1) } try { $Events = Get-WinEvent -MaxEvents 1000 -FilterHashTable $Search ` -ErrorAction silentlycontinue ` -ErrorVariable +Errors | Select Id, TimeCreated, Level, LevelDisplayName, Message, ProviderName, LogName } Catch { $ThisError = "$(get-date): Failed to get WinEvent $($_.ErrorDetails.Message) " $errors += $ThisError $ThisError>>$Logfile >>$Logfile } try { $Events += Get-WinEvent -MaxEvents 1000 -FilterHashTable $FailedLogins ` -ErrorAction silentlycontinue ` -ErrorVariable +Errors | Select Id, TimeCreated, level, LevelDisplayName, Message, ProviderName, LogName } Catch { $ThisError = "$(get-date): Failed to get WinEvent Security log $($_.ErrorDetails.Message) " $errors += $ThisError $ThisError>>$Logfile } if ($errors[0] -ilike "*No events were found*" -and $errors.Count -eq 1) { $Errors = @() } if (($Events.Count -gt 0) -and ($Errors.count -eq 0)) { Write-SqlTableData -inputData $Events ` -ServerInstance $SQLInstance -database $SQLDatabase ` -Credential $SQLCredentials ` -SchemaName "dbo" -TableName $StagingTableName -Force ` -ErrorAction silentlycontinue ` -ErrorVariable +Errors } $sql =@" USE [$SQLDatabase] GO IF Object_Id('dbo.$DestinationTableName') IS NULL begin CREATE TABLE [dbo].[$DestinationTableName]( [Id] [INT] NOT NULL, [TimeCreated] [DATETIME2](7) not NULL, [Level] [TINYINT] NOT NULL, [LevelDisplayName] [NVARCHAR](40) not NULL, [Message] [NVARCHAR](4000) NOT NULL, [ProviderName] [NVARCHAR](40) NOT NULL, [LogName] [NVARCHAR](40) NOT NULL ) ON [PRIMARY] END GO INSERT INTO [$DestinationTableName](Id, TimeCreated, [Level], LevelDisplayName, [Message], ProviderName, LogName) SELECT $StagingTableName.Id, $StagingTableName.TimeCreated, $StagingTableName.Level, $StagingTableName.LevelDisplayName, Left($StagingTableName.Message,4000), Left($StagingTableName.ProviderName,40), Left($StagingTableName.LogName,40) FROM $StagingTableName LEFT OUTER JOIN [$DestinationTableName] ON $DestinationTableName.Id = $StagingTableName.Id AND $DestinationTableName.TimeCreated = $StagingTableName.TimeCreated WHERE $DestinationTableName.message IS null TRUNCATE TABLE $StagingTableName --because you don't need that data again. "@ if ($Errors.count -eq 0) { Invoke-Sqlcmd -Query $sql -ServerInstance $SQLInstance ` -Credential $SQLCredentials -database $SQLDatabase ` -ErrorAction silentlycontinue ` -ErrorVariable +Errors } <# We collect all the soft errors and deal with them here.#> if ($errors.Count -gt 0) { $errors | foreach { "$((Get-Date).ToString()): $($_) the task was aborted">>$Logfile; } }; "$(get-date): checked for errors, found $($events.Count)">>$Logfile
我將其放在Windows任務計劃程序上,每隔5分鐘運行一次,這就是為什么將運行此腳本產生的所有錯誤和警告通過管道傳輸到本地錯誤日志文件的原因(否則您將看不到它們!)
這是一個最好的過程,需要分幾個階段進行,并且要一直進行測試。首先,在計劃程序中,在服務器上的PowerShell ISE中運行任務,并以您將分配為運行PowerShell任務的用戶ID登錄。然后,以同一用戶的身份使用PowerShell控制臺,再使用命令控制臺,最后在調度程序上,以五分鐘的間隔運行它,并檢查本地錯誤日志中是否有任何錯誤和報告。
確保此功能正常運行的明顯測試是嘗試使用錯誤的ID或密碼登錄服務器,并查看events表中是否有任何內容。
您還可以添加各種虛假錯誤以確保將其記錄下來。
New-EventLog –LogName Application –Source PowerShellScript Write-EventLog -LogName "Application" ` -Source PowerShellScript ` -EventID 3001 -EntryType Warning ` -Message "A melancholy misadventure has struck my code." Write-EventLog -LogName "Application" ` -Source PowerShellScript ` -EventID 3001 -EntryType Error ` -Message "My code has been sadly struck by misfortune."
五分鐘后,您需要在SSMS中檢查事件查看器和SQL Server數據庫,以確保所有事件都已轉移。
一旦確定這是可行的,就可以在SQL Monitor端進行操作。
本教程內容尚未完結,敬請期待下半部分內容——創建SQL Monitor自定義指標~感興趣的朋友可以下載SQL Monitor正式版嘗試一下~
相關內容推薦:
監控工具SQL Monitor:使用SQL Monitor跟蹤數據庫上的活動會話數
使用SQL Server監控工具SQL Monitor,監視Azure SQL數據庫的性能問題(上)
使用SQL Server監控工具SQL Monitor,監視Azure SQL數據庫的性能問題(下)
想要購買SQL Monitor正版授權,或了解更多產品信息請點擊
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn