PowerShellとセキュリティ監査
ハブラナロッドへのご挨拶! PowerShellを使用したWindowsシステムのシステム管理のルーチンルーチンを容易にする方法を共有したいと思います。
ある晴れた日、私は、ワークステーションとしてターミナルサーバーを使用するユーザーのアクティビティを毎日監視するタスクに直面しました。 Windowsの管理ツールの一部である「イベントビューアー」は、サーバーの状況を監視するのに最も便利な方法ではないと言って、自分の意見だけでなく表明すると思います。 はい、関心のあるイベントのみを除外するフィルターがありますが、この情報の表示形式を変更する便利な方法はありません。 その結果、PowerShellを使用してセキュリティログイベントを解析するというアイデアが生まれました。
イベントのリストを取得するには、Get-EventLogコマンドが必要です。このパラメーターの1つはログの名前で、この場合はセキュリティです。

このコマンドはログ全体の内容を表示しますが、これは基本的に私には適していません。 しかし、すべてがそれほど悪くはありません。スクリーンショットに表示されるのはテキストだけでなく、オブジェクトであり、PowerShellのフレームワーク内で必要なすべてのプロパティを設定できます。 これらのオブジェクトのプロパティを取得すると、Get-Memberコマンドレットが許可されます。
Get-EventLog security | Get-Member
実行する
Get-EventLog security | Get-Member
Get-EventLog security | Get-Member
では、Get-EventLogによって表示されるすべてのオブジェクトのプロパティのリストを取得します。

プロパティのリストがわかれば、Get-EventLogの結果を操作できます。 たとえば、今日のすべてのイベントの一覧を取得するには、Get-EventLogコマンドレットのパラメーター、つまり
-after
パラメーターを使用するのが最も簡単な方法です。 パラメータの完全なリストは、
ここにあります 。 その結果、
Get-EventLog security -after (Get-date -hour 0 -minute 0 -second 0)
取得します。Get-Dateコマンドレットは現在の日付と時刻を表示しますが、hour、minute、secondパラメーターは最初からの時間出力を指定します今日。 その結果、今日発生したイベントのリストを取得します。 すでに優れていますが、それでもそうではありません。
RPDプロトコルを使用してサーバーにログインしたすべてのユーザーのリストを取得する必要があるため、EventIDとEntryTypeの値を調べることになりました。 次に、これらの値の完全なリストは提供しません。
EventID値
各ログインイベントは、特定のログインタイプによって補完されます。そのリストを以下にリストします。
- 528-コンピューターへのユーザーログインに成功しました。
- 529-ログイン失敗。 無効なユーザー名またはパスワード。
- 530-ログインの失敗。 有効な時間間隔外のユーザーアカウントでログインしようとしました。
- 531-ログイン失敗。 無効なユーザーアカウントを使用してログインしようとしています。
- 532-ログイン失敗。 古いユーザーアカウントを使用してログインしようとしました。
- 533-ログインの失敗。 このコンピューターへのログオンを許可されていないユーザーにログオンしようとしました。
- 534-ログイン失敗。 不正なログインタイプでログインを試みました。
- 535-ログイン失敗。 指定されたアカウントのパスワードの有効期限が切れています。
- 536-ログインの失敗。 Net Logonサービスは無効になっています。
- 537-ログイン失敗。 他の理由でシステムへのアクセスに失敗しました(場合によっては、システムへのアクセスを拒否した理由が不明な場合があります)。
- 538-ユーザーのログアウトプロセスが完了しました。
- 539-ログイン失敗。 ログイン試行中、ユーザーアカウントはロックされます。
- 540-ネットワークへのユーザーログインに成功しました。
- 541 —ローカルコンピューターと登録されたピアID(信頼できるアソシエーションを確立する)との間の基本的なIKE認証モードが完了するか、高速モードがデータチャネルを確立しました。
- 542-データチャネルは無効です。
- 543-メインモードが無効になっています(この理由は、信頼できる接続(デフォルトは8時間)、ポリシーの変更、またはピアの終了の期間を制限する時間間隔の終了かもしれません)。
- 544-パートナーが有効な証明書を提供しなかったか、署名が認証されていないという事実による基本認証モードの失敗。
- 545-Kerberosエラーまたは無効なパスワードが原因で、プライマリ認証モードが失敗しました。
- 546-パートナーからの受け入れられないオファーが原因で、信頼できるIKE接続を作成できない。 無効なデータを含むパケットを受信しています。
- 547-IKE接続確立手順中の失敗。
- 548-ログインの失敗。 信頼されたドメインから受信した信頼性識別子(SID)は、クライアントのドメインアカウントのSIDと一致しません。
- 549-ログイン失敗。 信頼されていない名前空間に関連付けられているすべてのSIDは、フォレスト認証中に除外されました。
- 550-サービスに対する攻撃の可能性を示す通知メッセージ。
- 551-ユーザーがログアウトプロセスを開始しました。
- 552-ユーザーは、以前は別のユーザーとしてログインしていたにもかかわらず、正しい資格情報を使用してコンピューターに正常にログオンしました。
- 682-ユーザーは、切断されたターミナルサーバーセッションに再接続されます。
- 683-ユーザーはログアウトせずにターミナルサーバーセッションから切断されます(このイベントは、ユーザーがネットワーク経由でターミナルサーバーセッションに接続したときに生成されます。ターミナルサーバーに表示されます)。
EntryType値
- 2-インタラクティブ。 ユーザーがコンピューターに正常にログインしました。
- 3-ネットワーク。 ユーザーまたはコンピューターがネットワーク経由でコンピューターにログオンしました。
- 4-バッチ。 エントリのパケットタイプは、パケットサーバーによって使用されます。パケットサーバーでは、ユーザーに代わってプロセスが実行されますが、ユーザーの直接の介入は必要ありません。
- 5-サービス。 サービスはサービスコントロールマネージャーによって開始されます。
- 7-ロック解除。 このワークステーションはロック解除されています。
- 8-NetworkCleartext。 ユーザーがネットワーク経由でコンピューターにログオンしました。 ユーザーパスワードは、未切断の形式で認証パケットに渡されました。 統合認証は、ハッシュされたアカウントをすべてネットワークに送信する前にパックします。 資格情報は、クリアテキストでネットワーク経由で送信されません。
- 9-NewCredentials。 訪問者は現在のトークンを複製し、発信接続用の新しいアカウントを指定しました。 新しいログインセッションは同じローカルIDを持ちますが、ネットワーク接続に異なるアカウントを使用します。
- 10-RemoteInteractive。 ユーザーがターミナルサービスまたはリモートデスクトップを使用してこのコンピューターにリモートでログオンしました。
- 11-CachedInteractive。 ユーザーがコンピューターにローカルに保存されたネットワーク資格情報でこのコンピューターにログオンしました。 ドメインコントローラーは、資格情報の確認には使用されませんでした。
この情報は主にこの
ソースから取得され
ます 。 取得した情報から、RDPを介したコンピューターへの入力に対応するEventID = 528およびEntryType = 10のイベントが必要であると結論付けることができます。 チームを少し変更しましょう。
Get-EventLog security -message "* :?10*" -after (Get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }
-message
パラメーターは、イベントのメッセージを
-message
反映します。このメッセージには、 "Entry type"(2003年のロシア語バージョンがあるため、 "Input Type")が含まれます。
コマンドレットのパラメーターにGet_EventLog
-EventID
が見つからなかったため、オブジェクトプロパティのプロパティを使用する必要がありました。
$_
は、最初に表示されるオブジェクト自体を意味します
-eq
は、値が等しいことを意味します。この場合、528
実行の結果は次のようになります。

一般的に、必要なものはありますが、間違った情報のみが表示されます。 修正します。 オブジェクトの3つのパラメーターは、私にとって重要です。これらは、時間、ユーザー名、IPアドレスです。 将来、オブジェクトを作成し、興味のあるデータを入力してください。 スクリプト「test.ps1」を作成しました。 チーム全体が入力するのに問題があります。
$Events = Get-EventLog security -message "* :?10*" -after (get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }
$Data = New-Object System.Management.Automation.PSObject
$Data | Add-Member NoteProperty Time ($null)
$Data | Add-Member NoteProperty UserName ($null)
$Data | Add-Member NoteProperty Address ($null)
$Events | %{
$Data.time = $_.TimeGenerated
$message = $_.message.split("`n") | %{$_.trimstart()} | %{$_.trimend()}
$Data.UserName = ($message | ?{$_ -like ":*"} | %{$_ -replace "^.+:."} )
$Data.Address = ($message | ?{$_ -like " :*"} | %{$_ -replace "^.+:."})
$data
}
このコードを詳しく見てみましょう。
$Events = Get-EventLog security -message "* :?10*" -after (get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }
$Events = Get-EventLog security -message "* :?10*" -after (get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }
-イベントを選択した結果を変数に
$Events = Get-EventLog security -message "* :?10*" -after (get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 528 }
します。これにより、将来的にイベントを処理するのに便利です。
次に、時間、ユーザー名、アドレスの3つの値を含む将来のテーブルの「テンプレート」を作成します。
$Data = New-Object System.Management.Automation.PSObject
$Data | Add-Member NoteProperty Time ($null)
$Data | Add-Member NoteProperty UserName ($null)
$Data | Add-Member NoteProperty Address ($null
$Data = New-Object System.Management.Automation.PSObject
$Data | Add-Member NoteProperty Time ($null)
$Data | Add-Member NoteProperty UserName ($null)
$Data | Add-Member NoteProperty Address ($null
)
$Events | %{}
$Events | %{}
-選択結果に含まれる各オブジェクトを通過します
$Data.time = $_.TimeGenerated
時間を
$Data.time = $_.TimeGenerated
$message = $_.message.split("`n") | %{$_.trimstart()} | %{$_.trimend()}
$message = $_.message.split("`n") | %{$_.trimstart()} | %{$_.trimend()}
。
$Data.UserName = ($message | ?{$_ -like ":*"} | %{$_ -replace "^.+:."} )
$Data.Address = ($message | ?{$_ -like " :*"} | %{$_ -replace "^.+:."})
$Data.UserName = ($message | ?{$_ -like ":*"} | %{$_ -replace "^.+:."} )
$Data.Address = ($message | ?{$_ -like " :*"} | %{$_ -replace "^.+:."})
次に、新しく形成された配列で、行 "ユーザー:「および」ソースネットワークアドレス:」、および-replaceはこれらの正規表現をさらに削除し、情報自体を残します。
コマンド
.\test.ps1
を使用してスクリプトを実行します。 (ご覧のとおり、PSスクリプトを実行するには、現在の作業フォルダーにある場合でもパスを指定する必要があります):

スクリプトが開始されなかった場合、PoShがスクリプトを実行するように構成されていない可能性があります。
Set-ExecutionPolicy RemoteSignet
ます。
かなり良いように見えますが、スクリプトを改善できると思います。 便宜上、パラメータを設定し、IPアドレスマスクを使用して色付きの線を強調表示する機能を追加します。
param ($key1,$val1,$val2,$val3,$val4,$val5,$val6)
if ($val1 -eq $null) {$val1=0};
$mydate = Get-date -hour 0 -minute 0 -second 0;
if ($key1 -eq "year") { $mydate = (Get-date -hour 0 -minute 0 -second 0 -day 1 -month 1); $mydate = $mydate.addyears(-$val1); };
if ($key1 -eq "month") { $mydate = (Get-date -hour 0 -minute 0 -second 0 -day 1); $mydate = $mydate.addmonths(-$val1); };
if ($key1 -eq "day") { $mydate = $mydate.adddays(-$val1) };
if ($key1 -eq "date") { $mydate = (Get-date -hour 0 -minute 0 -second 0 -day $val1 -month $val2 -year $val3); }; #
if ($val4 -eq $null) {$Events = Get-EventLog security -message "* :?10*" -after ($mydate) | ?{$_.eventid -eq 528 }}
if ($val4 -ne $null) {$Events = Get-EventLog security -message "* :?10*" -after ($mydate) -before (get-date -hour 0 -minute 0 -second 0 -day $val4 -month $val5 -year $val6) | ?{$_.eventid -eq 528 }}
$Data = New-Object System.Management.Automation.PSObject
$Data | Add-Member NoteProperty Time ($null)
$Data | Add-Member NoteProperty UserName ($null)
$Data | Add-Member NoteProperty Address ($null)
$Events | %{
$Data.time = $_.TimeGenerated
$message = $_.message.split("`n") | %{$_.trimstart()} | %{$_.trimend()}
$Data.UserName = ($message | ?{$_ -like ":*"} | %{$_ -replace "^.+:."} )
$Data.Address = ($message | ?{$_ -like " :*"} | %{$_ -replace "^.+:."})
$textcolor = $host.ui.rawui.foregroundcolor
$host.ui.rawui.foregroundcolor = "red"
if ($data.address -like "192.168.0*") {$host.ui.rawui.foregroundcolor = "DarkGreen"}
if ($data.address -like "10.*") {$host.ui.rawui.foregroundcolor = "yellow"}
$data
$host.ui.rawui.foregroundcolor = $textcolor
}
param ($key1,$val1,$val2,$val3,$val4,$val5,$val6)
-スクリプトに渡されるパラメーターを定義します。
if ($key1 -eq "day") { $mydate = $mydate.adddays(-$val1) };;
転送されたパラメーターがキーに準拠しているかどうかを確認し、キーが一致する場合は、指定されたパラメーターに従って日付を調整します。 この場合、「日」キーがパラメーターとして渡され、引数を使用して特定の日数前に日付を変換します。 つまり ログは一定の日数表示され、残りの条件は類推により、1か月と1年満たされます。 「日付」キーが指定されている場合、スペースで示される特定の日付が開始点として使用されます(例:「01 05 2011」)。スペースで別の日付も指定すると、これらの日付に示される特定の期間が表示されます。 情報をカラーで出力するには、パラメータ-backgroundcolorおよび-foregroundcolorを持つWrite-Hostコマンドレットを使用することが当初計画されていましたが、最終的にはオブジェクトの出力に馴染みがないため、それを放棄しなければなりませんでした。

わかりやすくするために、内部ローカルネットワークの表示を緑色、外部の黄色、その他のなじみのないアドレスをすべて赤にしました。
そして、
{$_.eventid -eq 529 }
を設定すると、不正なパスワードを使用したすべてのログイン試行になります。

リストはかなり長く、1日に2、3回、ファイアウォール上のこのような悪人をチェックしてブロックすると便利です。
その結果、最小限の変更でスクリプトを調整して、イベントログに含まれる情報を簡単に表示できます。