PowerShellで重要なWindowsセキュリティイベントを追跡する方法


多くの組織は、業務を遂行するためにMicrosoftのテクノロジーに依存しています。同時に、脅威行為者はWindowsなどのオペレーティングシステムを悪用することができます。幸いなことに、WindowsはOSのセキュリティイベントを記録し、このような行動を追跡するのに役立ちます。

Windowsによって生成されるセキュリティイベントは、インシデント対応プロセスにおいて重要なリソースとなります。MicrosoftのWindowsイベントビューアなどのツールを使用することで、キャプチャされたイベントを確認するためのアクセス権が提供されますが、混雑したログを手動でスクロールして異常を検出することは現実的ではありません。

この記事では、監査ポリシー、Windowsイベントログ、およびPowerShellを使用してセキュリティ侵害の可能性を追跡する方法について学びます。

前提条件

この記事は、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はそのアクションを1つ以上のイベントログとして記録します。Windowsイベントログは、デフォルトでファイルシステムに%SystemRoot%\system32\winevt\logsディレクトリに保存されます。この場所は、対応するイベントログのEventLogレジストリサブキーを変更することで変更できます。

システム上の最も重要なイベントログ(Application、Security、およびSystem)の保存場所を確認したい場合は、以下のコードをPowerShellコンソールにコピーして貼り付けるか、スクリプトとして保存してください。

セキュリティログファイルの保存場所にアクセスするには、管理者としてコードを実行する必要があります。

#アプリケーション、セキュリティ、およびシステムログを配列で表示します。
 $arrLogs = @(
     "Application"
     "Security"
     "System"
 )
 #ForEach-Objectコマンドレットを使用して、各対応するログをGet-ItemPropertyコマンドレットで対象にします。
 $arrLogs | ForEach-Object {
     #Get-ItemPropertyコマンドレットを使用して、アプリケーション、セキュリティ、およびシステムログの構成済みファイルパスをリストします。
     Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\$_ -Name File | Select-Object PSChildName,File
 }

次のスクリーンショットは、コードの予想される出力を示しており、ApplicationSecurity、およびSystemログファイルのログ名と保存場所を表示しています。

Application, Security, and System audit log location

Audit Policies: Defining Events to Record

デフォルトでは、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コンソールを開き、以下のコマンドを実行します。このコマンドは、ログオンのサブカテゴリに属するすべてのイベント(成功および失敗)の記録を開始します。

ログオンのサブカテゴリを構成すると、システムは以下のイベントを記録します:

#ログオンイベントを設定して成功/失敗のアクティビティをキャプチャします。
auditpol /set /subcategory:"Logon" /success:enable /failure:enable

ベストプラクティスの監査ポリシー設定をサポートするために、Center for Internet Security (CIS) BenchmarksDefense Information Systems Agency (DISA) Security Technical Implementation Guides (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.

期待される出力を受け取っていない場合は、Secondary Logon サービスが実行中であることを確認してください。

PowerShell で Windows イベントにアクセスする

これで少なくとも 35 個の Windows セキュリティイベントがあることが確認できたので、PowerShell の Get-WinEvent コマンドレットを使用してそれらを見つける方法について説明します。

おそらく PowerShell の Get-EventLog コマンドレットはおなじみかもしれませんが、これもプログラムでイベントログにアクセスするために使用されます。 Get-EventLog は非推奨の Win32 アプリケーションプログラミングインターフェイス(API)を使用しており、この投稿では説明しません。

管理者として PowerShell コンソールを開き、以下に示すように Get-WinEvent コマンドレットを呼び出し、FilterHashtable および MaxEvents パラメーターを渡します。

以下のコマンドは、システムのセキュリティログ(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 イベントには、より深い分析に使用できる貴重なプロパティがあります。

XML 形式の Windows イベント

Windows がイベントを記録すると、それは XML 形式で保存されます。それならば、なぜ Get-WinEvent コマンドが通常の PowerShell オブジェクトを返したのでしょうか? Get-WinEvent コマンドレットは、ネイティブの Windows API を読み込み、イベントを PowerShell オブジェクトに変換して機能を向上させています。

各 Windows イベントには、特定のXML スキーマまたは構造に従うさまざまな属性があります。

以下で、各イベントが特定の構造に従っていることがわかります:

  • name – プロパティの名前
  • inType – 入力タイプの定義またはイベントが値を受け入れる方法
  • outputType – 出力タイプの定義またはイベントが記録される方法

PowerShellでイベントXMLテンプレートを見つける

前述のように、すべてのWindowsセキュリティイベントはXMLに格納されており、特定のスキーマがありますが、そのスキーマはどのように見えるのでしょうか?さて、それを見つけましょう。

以前のセクションの1つで、セキュリティイベントログでID 4625のいくつかのイベントを生成しました。このタイプのイベントにはそれにのみ適用される特定の属性があります。これらの属性とテンプレートの外観を見つけるには:

1. PowerShellコンソールを管理者として開きます(まだ開いていない場合)。

2. ListProviderパラメーターを使用して、Windowsがセキュリティイベントログにイベントを記録するために使用するプロバイダーを指定し、Eventsプロパティのみを返すように、再度Get-WinEventを実行します。

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オブジェクトのプロパティではありません。このプロパティは配列に格納されます。

# Event ID 4625の最初のインスタンスのイベントプロパティ配列を出力
 $eventProperties = (Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 1).properties
 $eventProperties

以下のスクリーンショットの左側には、上記のコマンドの出力があります。配列には、スクリーンショットの右側のXMLテンプレートの各XML属性のが含まれています。

スクリーンショットに表示されているコードの出力によれば、AtaBlogUserTargetUserName)ユーザーのシステムDesktop-XXXXXWorkstationName)からの認証失敗が発生し、IPアドレス::1IpAddress)を使用しています。

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

おそらくTargetUserNameイベントプロパティの値だけを返すことを希望しているかもしれません。すでにすべてのイベントプロパティを$eventPropertiesという変数に保存しているので、TargetUserNameの値を保持している5番目のインデックスを参照します。

個々のイベントプロパティオブジェクトのvalueプロパティを参照して、値(AtaBlogUser)だけを返す必要があります。 $eventProperties[5].value

$eventProperties[5].value
Event attribute property positions

このセクションで説明されている方法は、このポストの後続セクションで、以前にシミュレートしたブルートフォースの試みを追跡するために使用されます。

ブルートフォース攻撃の検出

あなたは今、PowerShellのスキルを使用して、この投稿で再現したブルートフォース攻撃を追跡する準備が整いました!テストのために、特定の時間枠に基づいてブルートフォース攻撃を追跡する様子をシミュレートしましょう。

例えば、組織が重要なWindows Serverに管理アカウントを使用しようとする試みがあるとの通知を受けました。この活動は昨日から始まりました。過去24時間に発生したイベントID4625:アカウントのログオンに失敗しましたの数を見つけ、各イベントのログオンタイプを判別する必要があります。

1. 過去24時間のWindowsセキュリティログ(LogName="Security")でイベントID 4625(ID=4625)を持つすべてのイベントを見つけます(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変数内の各オブジェクトを読み取り、興味深いプロパティのみを収集し、それらを1行に連結します。

#Event ID 4625のすべてのインスタンスからTargetUserName、LogonType、WorkstationName、およびIpAddressイベントプロパティを抽出します。
 $events | ForEach-Object {
     ## プロパティオブジェクトプロパティを参照します
     ## インデックス5、10、13、および19の値のみを返します
     ## すべての値をカンマで結合して連結します
     $_.properties[5,10,13,19].value -join ", "
 }

次のスクリーンショットは、コードの予想される出力の要約バージョンを示しており、TargetUserNameLogonTypeWorkstationName、およびIpAddressのカンマ区切りのリストを詳細に説明しています。

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 – 呼び出し元が現在のトークンをクローン化し、アウトバウンド接続のための新しい資格情報を指定しました。新しいログオンセッションは同じローカルIDを持ちますが、他のネットワーク接続には異なる資格情報を使用します。

10 – RemoteInteractive – 呼び出し元が現在のトークンをクローン化し、アウトバウンド接続のための新しい資格情報を指定しました。新しいログオンセッションは同じローカルIDを持ちますが、他のネットワーク接続には異なる資格情報を使用します。

11 – CachedInteractive – このコンピュータにネットワーク資格情報を使用してログオンしたユーザー。ドメインコントローラーは資格情報を確認するために連絡されませんでした。

今、各LogonTypeの理解が深まったので、出力で数値ではなく、より記述的な文字列を見たいと思います。PowerShellで”maps”を作成するには、ハッシュテーブルを使用します。

$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ハッシュテーブルをForEach-Objectと組み合わせて、以下に示すようにユーザーフレンドリーなLogonTypeの値を持つプロパティのみを返すスクリプトを作成します。Format-Tableコマンドレットは、PowerShellの応答をテーブルとしてフォーマットすることで、ユーザーフレンドリーな出力に追加します。

#Get-WinEventを使用して、イベントID 4625の各ログインインスタンスのプロパティにアクセスします
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
##数値値を文字列"map"に変換します
$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 
    }
} | Format-Table -Wrap

この時点で、PSCustomObjectタイプのオブジェクトを返すスクリプトがあり、さまざまな種類の分析を実行できます!このチュートリアルの分析を最終的に終了するには、TargetUserNameによる認証失敗の試行を優先します。 TargetUserNameプロパティによって失敗を優先させるには、上記のコードをGroup-Objectコマンドレットと組み合わせます。 Sort-ObjectおよびそのDescendingスイッチを使用して、最も問題のあるユーザーを特定します。

#Get-WinEventを使用してEvent ID 4625の各ログされたインスタンスのプロパティにアクセスする
$events = Get-WinEvent -FilterHashTable @{LogName="Security";ID=4625;StartTime=((Get-Date).AddDays(-1).Date);EndTime=(Get-Date)}
## 数値を文字列 "map" に変換する
$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/