如何使用PowerShell跟踪重要的Windows安全事件


许多组织依赖Microsoft技术来完成工作。与此同时,威胁行为者可能会利用诸如Windows之类的操作系统。幸运的是,Windows会记录操作系统安全事件,以帮助您追踪此类行为。

由Windows生成的安全事件在事件响应过程中充当关键资源。诸如Microsoft的Windows事件查看器之类的工具为您提供了访问权限,以查看捕获的事件,但通过手动滚动浏览拥挤的日志来检测异常是不切实际的。

在本文中,您将学习如何通过学习审计策略、Windows事件日志,并使用PowerShell分析安全事件来追踪Windows中潜在的安全漏洞。

先决条件

本文旨在传达有关如何使用PowerShell分析Windows安全事件的信息。如果您想要跟随任何演示,您将需要:

  • A Windows 10+ PC – This PC will be used to generate and track down potential security events in the event log. This tutorial will be using Windows PowerShell 5.1.
  • 在Windows PC上拥有管理员权限
  • A PowerShell code editor such PowerShell ISE or Visual Studio (VS) Code.

Windows存储安全事件的位置

當在Windows操作系統上執行動作時,Windows會將該動作記錄為一個或多個事件日誌中的事件。 Windows事件日誌默認存儲在文件系統中的%SystemRoot%\system32\winevt\logs目錄中。 可以通過修改相應事件日誌的EventLog註冊表子鍵來更改此位置。

如果您想查看系統上存儲最重要的事件日誌(應用程序、安全性和系統)的位置,請將以下代碼複製並粘貼到PowerShell控制台,或將其保存為腳本。

要訪問安全性日誌文件的存儲位置,您需要以管理員身份運行代碼。

#以數組形式顯示應用程序、安全性和系統日誌。
 $arrLogs = @(
     "Application"
     "Security"
     "System"
 )
 #使用ForEach-Object cmdlet來針對每個相應的日誌使用Get-ItemProperty cmdlet。
 $arrLogs | ForEach-Object {
     #使用Get-ItemProperty cmdlet列出應用程序、安全性和系統日誌的配置文件路徑。
     Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\$_ -Name File | Select-Object PSChildName,File
 }

下面的截圖顯示了代碼的預期輸出,顯示了應用程序安全性系統日誌文件的日誌名稱和存儲位置。

Application, Security, and System audit log location

審核策略:定義要記錄的事件

默認情況下,Windows不會捕獲可能需要檢測或調查入侵的所有安全事件。要控制Windows的記錄內容,您需要定義並應用審計策略。審計策略是傳遞給Windows的一組指令,告訴它要記錄哪些事件。

有幾種不同的方法來分配和使用審計策略,例如群組策略。如果您需要在多台計算機上實施審計策略,群組策略是一種很好的方法。但在本文中,您將僅限於一個設備,因此您將使用auditpol工具。auditpol工具已安裝在Windows上,允許您在Windows系統上查找和設置審計策略。

查找審計策略

例如,要查找Windows系統上所有審計策略的狀態,請使用下面所示的/get參數。使用/category參數後跟通配符,告訴auditpol查找所有審計策略的狀態;而不僅僅是與特定類別或子類別匹配的一個。

#獲取系統的審核政策配置。
auditpol /get /category:*

以下截圖顯示代碼預期輸出的截斷版本,顯示帳戶管理審核政策類別、子類別和狀態(設定)。

Audit policy category, subcategory, and configuration

A Setting that is configured as No Auditing means that all events associated with that audit policy subcategory will not be logged.

設置審核政策

auditpol工具不僅可以查看審核政策設置,還可以使用auditpol /set命令修改它們。為了演示本教程中的未來部分,打開以管理員身份運行的PowerShell控制台,然後運行下面的命令。此命令開始記錄所有屬於Logon子類別的事件(成功和失敗)。

配置Logon子類別會強制系統記錄事件:

#設置登錄事件以捕獲成功/失敗活動。
auditpol /set /subcategory:"Logon" /success:enable /failure:enable

有很多資源可用於協助您進行最佳實踐的審計策略配置,包括互聯網安全中心(CIS)基準,以及國防信息系統局(DISA)安全技術實施指南(STIG),以及Microsoft發布的指南。

生成用於分析的登錄失敗日誌

本文將是一篇教程,並期望您跟著操作。如果您已經配置了Windows以審計超過登錄事件,那麼現在讓我們生成一些安全事件,以便稍後進行分析。更具體地說,讓我們生成35次失敗的登錄嘗試,這些嘗試將被記錄在系統的安全日誌中,以模擬暴力破解活動。

1. 打開您最喜歡的代碼編輯器。

2. 複製以下代碼並粘貼到代碼編輯器中。此代碼片段嘗試使用虛假的用戶名和密碼使用 Start-Process 命令開啟 PowerShell.exe 進程。

#定義 5 個用戶名,記錄登錄失敗。
 $arrUsers = @(
     "AtaBlogUser1"
     "AtaBlogUser2"
     "AtaBlogUser3"
     "AtaBlogUser4"
     "AtaBlogUser5"
 )
 #使用 ForEach-Object 循環遍歷用戶名,為每個生成一個登錄失敗。
 $arrUsers | ForEach-Object {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential($_, $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
 }
 #為 AtaBlogUser 用戶生成 30 次登錄失敗。
 $i = 0
 Do {
     $securePassword = ConvertTo-SecureString "AtA810GRu13Z%%" -AsPlainText -Force 
     $storedCredential = New-Object System.Management.Automation.PSCredential("AtaBlogUser", $securePassword)
     Start-Process -FilePath PowerShell -Credential $storedCredential
     $i++
 } Until ($i -eq 30)

3. 將 PowerShell 腳本保存為 Invoke-BogusEvents.ps1 或其他您喜歡的名稱,然後執行該腳本。

執行時,您將注意到預期的錯誤重複出現 35 次,指示 用戶名或密碼不正確

Authentication failure due to incorrect user name or password.

如果未收到預期的輸出,請確保次要登錄服務處於運行狀態。

使用 PowerShell 訪問 Windows 事件

現在,您確定至少有 35 個 Windows 安全事件,讓我們深入了解如何使用 PowerShell 的 Get-WinEvent 命令找到它們。

您可能熟悉 PowerShell 的 Get-EventLog 命令,它也用於以編程方式訪問事件日誌。 Get-EventLog 使用了一個已棄用的 Win32 應用程序編程接口(API),本文將不討論該部分。

打開 PowerShell 控制台作為管理員並調用 Get-WinEvent 命令,並傳遞 FilterHashtableMaxEvents 參數如下所示。

以下命令查詢您系統的安全日誌(LogName='Security')中的 事件ID 4625ID=4625)並返回前 10 個最新實例(MaxEvents 10)。

#過濾安全日誌以獲取事件ID 4625的前10個實例
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 10

如果成功,您應該看到類似以下的輸出:

10 instances of Event ID 4625

使用 Get-WinEvent 訪問事件屬性

在上面的部分中,您使用了 Get-WinEvent 來查看 Windows 安全事件的高級信息,但是 Windows 事件包含更多信息。每個 Windows 事件都有寶貴的屬性,您可以用於進一步的分析。

Windows 事件作為 XML

當 Windows 記錄一個事件時,它以 XML 格式存儲。如果是這種情況,那麼為什麼您的 Get-WinEvent 命令返回典型的 PowerShell 對象呢?Get-WinEvent 命令讀取本機 Windows API,並將事件轉換為 PowerShell 對象,以增加功能性。

每個 Windows 事件都有各種屬性,遵循特定的 XML 結構

您將看到,每個事件都遵循一個特定的結構,具有三個屬性:

  • 名稱 – 屬性的名稱
  • inType – 輸入類型定義或事件如何接受值
  • outputType – 輸出類型定義或事件如何記錄

使用 PowerShell 尋找事件 XML 模板

如上所述,每個 Windows 安全事件都存儲在 XML 中並具有特定的模式,但該模式是什麼樣的?讓我們來找出。

在之前的某個部分中,您生成了安全事件日誌中 ID 為 4625 的幾個事件。這類事件具有僅適用於它的特定屬性。要查找這些屬性以及模板的外觀:

1. 如果您尚未打開 PowerShell 控制台,請以系統管理員身份打開 PowerShell 控制台。

2. 再次運行 Get-WinEvent,但這次使用 ListProvider 參數,指定 Windows 用於記錄事件到安全事件日誌的提供程序,並僅返回 Events 屬性。

Events 屬性包含列表提供程序已記錄的所有事件,並公開每個事件的 XML 模板。

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events
Get Win Event List Provider

3. 現在,您已經有代碼可以查找所有事件類型的模板,將其限制為僅返回與 ID 4625 相關聯的事件。

(Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625

4. 當您僅返回事件 ID 為 4625 的登錄事件類型時,將其限制為僅顯示如下的 Template 屬性。

# 獲取事件 ID 為 4625 的事件屬性的事件 XML 模板。
 ((Get-WinEvent -ListProvider 'Microsoft-Windows-Security-Auditing').Events | Where-Object -Property ID -eq 4625).Template

以下截圖顯示了代碼輸出的截斷版本,識別事件屬性名稱、輸入類型和輸出類型。您可以看到事件 ID 4625 具有帶有各種輸入和輸出定義的事件屬性。

下面的截圖突顯了事件 ID 4625 的 SubjectUserSid 屬性。此特定事件接受一個輸入類型(inType)為 win:SID,並將輸出(outType)呈現為 string,這是它在安全日誌中存儲的方式。

XML template example

PowerShell 如何將 XML 轉換為對象

既然您已經看到了 Windows 如何將事件存儲在 XML 中以及如何在 PowerShell 中查看這些模板,現在讓我們轉向 PowerShell 如何將該 XML 轉換為對象。

1. 再次運行 Get-WinEvent 命令以返回我們的事件 ID 4625。到目前為止,這沒什麼新的。請注意,PowerShell 只顯示四個屬性,TimeCreatedIdLevelDisplayNameMessage

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1
Get-WinEvent FilterHashtable

默認情況下,Get-WinEvent 命令不會將事件的 XML 數據源的所有屬性作為 PowerShell 對象返回。

2. 現在,將上述命令的輸出通過管道傳遞到 Select-Object 命令,並指定 Property 參數,傳遞值以顯示所有屬性。

Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1 | Select-Object -Property *

請注意,PowerShell 隱藏了許多不同的屬性。更具體地說,一個名為 Properties 的屬性。 Properties 屬性包含您之前在 XML 模板中看到的每個事件屬性的值。

Powershell hiding Properties

3. 限制Get-WinEvent命令的輸出以公開Properties屬性。此屬性以陣列形式儲存所有事件屬性,不是PowerShell物件屬性。

#輸出事件ID 4625的第一個實例的事件屬性陣列
 $eventProperties = (Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1).properties
 $eventProperties

下方截圖左側是上述命令的輸出。該陣列包含截圖右側XML模板中每個XML屬性的

截圖中代碼的輸出顯示,使用IP地址::1IpAddress),來自系統Desktop-XXXXXWorkstationName)的用戶AtaBlogUserTargetUserName)發生了身份驗證失敗。

Expected output correlating property values to Event ID 4625’s XML template.

也許您只想返回TargetUserName事件屬性的值。既然您已經在一個叫做$eventProperties的變數中儲存了所有事件屬性,參考第五個索引,該索引保存了TargetUserName的值。

您必須參考個別事件屬性物件上的value屬性來只返回值(AtaBlogUser)。 $eventProperties[5].value

$eventProperties[5].value
Event attribute property positions

本節描述的做法將在後續節中用於追踪您在本帖子中較早時模擬的暴力破解嘗試。

檢測暴力破解攻擊

你現在準備好利用你的 PowerShell 技能來追踪之前在這個帖子中複製的暴力攻擊了!讓我們通過模擬追踪一個在特定時間範圍內可能看起來是什麼樣子的暴力攻擊來考驗你的技能。

假設你收到了一個警報,你的組織認為有人試圖使用管理員帳戶登錄到一個重要的 Windows 伺服器上。這個活動是從昨天開始的。你必須發現過去 24 小時內發生的事件 ID 4625:帳戶登錄失敗 的次數,並確定每個事件的登錄類型。

1. 在 Windows 安全日誌中(LogName="Security")找到所有 ID 為 4625 的事件(ID=4625),範圍是過去的 24 小時(StartTime=((Get-Date).AddDays(-1).Date),結束時間為當前時間(Get-Date)。

$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1));EndTime=(Get-Date)}

2. 現在,計算存儲在變量中的所有事件,以確定是否有比預期更多的登錄失敗事件。

$events.Count

現在你應該看到一個數值,表示過去 24 小時內在安全事件日誌中找到事件 ID 4625 的次數。

3. 所以你已經確定了一次暴力攻擊發生了,現在追踪更多關於這些 Windows 安全事件的信息。為此,只返回你感興趣的每個事件的屬性。

如前所述,特定事件的每个值都存储在具有特定索引的数组中。此演示的有趣事件属性如下。

  • TargetUserName 索引: [5]
  • LogonType 索引: [10]
  • WorkstationName 索引: [13]
  • IpAddress 索引: [19]

以下代码示例读取$events变量中的每个对象,仅收集有趣的属性,并将它们连接成一行。

#从过去24小时内Event ID 4625的所有实例中提取TargetUserName、LogonType、WorkstationName和IpAddress事件属性。
 $events | ForEach-Object {
     ## 引用属性对象属性
     ## 仅返回属性数组中索引5、10、13和19的值
     ## 通过逗号将所有值连接在一起
     $_.properties[5,10,13,19].value -join ", "
 }

以下截图显示了代码预期输出的缩略版本,详细描述了逗号分隔的TargetUserNameLogonTypeWorkstationNameIpAddress的列表。

A truncated version of the code’s output, detailing TargetUserName, LogonType, WorkstationName, and IpAddress property values.

4. 正如您之前从XML模板中看到的,事件ID 4625的模板具有一个LogonType属性。该属性指示账户尝试进行身份验证的方法。通过进一步调查,您注意到LogonType偶尔会有所不同。

LogonType attribute

LogonType 的值是一個範圍在2到11之間的數值,但這代表什麼意思呢?您進行了一些研究,發現每個值代表的含義。

2 – 互動式 – 用戶登錄到這台計算機。

3 – 網絡 – 用戶或計算機通過網絡登錄到這台計算機。

4 – 批次 – 批次登錄類型用於批次服務器,其中進程可能代表用戶而無需直接介入。

5 – 服務 – 由服務控制管理器啟動的服務。

7 – 解鎖 – 此工作站已解鎖。

8 – NetworkCleartext – 用戶通過網絡登錄到這台計算機。用戶的密碼以未經雜湊的形式傳遞給身份驗證包。內置身份驗證包在將其傳遞到網絡之前對憑據進行雜湊。憑據不以純文本(也稱為明文)形式在網絡上傳輸。

9 – NewCredentials – 調用者克隆了其當前令牌並為出站連接指定了新憑據。新的登錄會話具有相同的本地身份,但對於其他網絡連接使用不同的憑據。

10 – RemoteInteractive – 調用者克隆了其當前令牌並為出站連接指定了新憑據。新的登錄會話具有相同的本地身份,但對於其他網絡連接使用不同的憑據。

11 – CachedInteractive – 用戶使用在計算機上本地存儲的網絡憑據登錄到這台計算機。未聯繫域控制器以驗證憑據。

現在您對每個LogonType有了很好的了解,不再希望在輸出中看到數值,而是希望看到更具描述性的字符串。在PowerShell中創建”映射”,可以使用hashtable。

$logonTypes = @{
     [uint32]2 = "Interactive"
     [uint32]3 = "Network"
     [uint32]4 = "Batch"
     [uint32]5 = "Service"
     [uint32]7 = "Unlock"
     [uint32]8 = "NetworkCleartext"
     [uint32]9 = "NewCredentials"
     [uint32]10 = "RemoteInteractive"
     [uint32]11 = "CachedInteractive"
 }

5. 將Get-WinEventLogonType的hashtable與ForEach-Object結合,創建一個腳本,僅返回您所需的屬性,並提供友好的LogonType值,如下所示。使用Format-Table cmdlet將友好的輸出格式化為表格形式,進一步增強了輸出效果。

#使用Get-WinEvent訪問每個事件ID 4625的日誌實例的屬性
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## 創建數值到字符串的"映射"
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## 開始處理$events陣列中的每個對象
$events | ForEach-Object {
    ## 在hashtable中查找數值
    $logonType = $logonTypes[$_.properties[10].value] 
    #創建自定義的PowerShell對象以輸出相關的事件屬性
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Format-Table -Wrap

到目前為止,您現在有一個返回PSCustomObject類型對象的腳本,可以進行多種不同類型的分析!要完成本教程的分析,請按TargetUserName的優先順序優化身份驗證失敗的嘗試。將上述代碼與Group-Object cmdlet結合使用,按照TargetUserName屬性進行優先順序排序。使用Sort-Object及其Descending開關,找出最高犯罪率的用戶。

#使用 Get-WinEvent 存取事件 ID 4625 的每個已記錄實例的屬性
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## 創建將數值轉換為字符串的“映射”
$logonTypes = @{
    [uint32]2 = "Interactive"
    [uint32]3 = "Network"
    [uint32]4 = "Batch"
    [uint32]5 = "Service"
    [uint32]7 = "Unlock"
    [uint32]8 = "NetworkCleartext"
    [uint32]9 = "NewCredentials"
    [uint32]10 = "RemoteInteractive"
    [uint32]11 = "CachedInteractive"
}
## 開始處理 $events 陣列中的每個物件
$events | ForEach-Object {
    ## 在雜湊表中查找數值
    $logonType = $logonTypes[$_.properties[10].value] 
    #創建自定義 PowerShell 物件以輸出相關的事件屬性
    [PSCustomObject]@{     
        TimeCreated = $_.TimeCreated     
        TargetUserName = $_.properties[5].value     
        LogonType = $logonType     
        WorkstationName = $_.properties[13].value     
        IpAddress = $_.properties[19].value 
    }
} | Group-Object -Property TargetUserName | Sort-Object -Property Count -Descending

做得好!您剛剛使用 PowerShell 偵測到了您在本文中早些時候模擬的暴力攻擊嘗試。根據輸出,AtaBlogUser 在過去的 24 小時內嘗試驗證失敗了 30 次!

AtaBlogUser Logon Failures

接下來的步驟

在本教程中,您學會了 Windows 如何記錄事件、如何為特定事件類型啟用事件記錄,以及如何構建一個 PowerShell 工具來查詢這些事件。

有了您現在的 PowerShell 腳本,您如何使其更好?您將如何利用今天學到的代碼來構建更好的工具?

Source:
https://adamtheautomator.com/windows-security-events/