
AD グループポリシー内の脆弱な設定を見つけるのに役立つ PowerShell スクリプト。(非推奨、代わりに Grouper2 を使用してください!)
GROUPERをもう使わないでください。GROUPER2を使ってください! https://github.com/l0ss/Grouper2
ADグループポリシー内の脆弱な設定を見つけるためのPowerShellスクリプトです。

Grouperは、ペネトレーションテスターやレッドチーム向けに設計されたPowerShellモジュールです(おそらくシステム管理者にも役立ちます)。Get-GPOReportコマンドレット(Microsoftのグループポリシーモジュールの一部)から出力される(通常非常にノイズの多い)XML出力をふるいにかけ、グループポリシーオブジェクト(GPO)で定義されている設定の中で、何か楽しいこと/悪いことをしようとする人に役立つ可能性のあるものをすべて特定します。
GrouperがGPOで見つけるものの例:
はい、かなり荒削りですが、あのひどい150MBのHTML GPOレポートを読む膨大な時間を節約してくれます。私にとってうまくいったので、あなたにもうまくいくかもしれません。
注:一部の関数名にはauditという単語が含まれているかもしれませんが、Grouperは明示的にベストプラクティス構成などを網羅的に監査するためのものではありません。もしそれが目的なら、Microsoft SCTやLGPO.exeなどを使用すべきです。
グループポリシーコマンドレットがインストールされたWindowsマシンでGPOレポートを生成します。 これらはデフォルトでドメインコントローラーにインストールされており、RSATを使用してWindowsクライアントにインストールするか、Windowsサーバーで「機能の追加」ウィザードから有効にできます。
Get-GPOReport -All -ReportType xml -Path C:\temp\gporeport.xml
Grouperモジュールをインポートします。
Import-Module .\grouper.psm1
Grouperを実行します。
Invoke-AuditGPOReport -Path C:\temp\gporeport.xml
Grouperが表示するポリシー設定を変更できるパラメータもいくつかあります。
-showDisabled
デフォルトでは、Grouperは現在有効でADのOUにリンクされているGPOのみを表示します。このパラメータはその動作を切り替えます。
-Online
デフォルトでは、GrouperはGet-GPOReportの実際のXML出力のみを扱い、ネットワーク通信を一切行わないため、かなり「opsecセーフ」です(ただし、この言葉は嫌いですが)。
-Onlineを指定して呼び出すと、Grouperはレポートが生成されたADドメインとの通信を必要とするチェックを有効にしますが、ファイルサーバーなどとの通信も含まれる可能性があります。これにより、GrouperはGPOが対象とするファイルのACLを報告したり、現在のユーザーがそのファイルに書き込み可能かどうかを確認したりするなどの便利な機能を実行できます。
-Level
Grouperには出力に適用できる3段階のフィルタリングレベルがあります。
使用法は簡単です。-Level 3、-Level 2など。
Get-GPOReportはrunas /netonlyを使用してドメイン非参加マシンでも問題なく動作します。いくつかの低権限の認証情報が必要ですが、それは想定内です。
次のようにします:
runas /netonly /user:domain\user powershell.exe
ドメインコントローラーと通信できるドメイン非参加マシン上で実行します。
次に、生成されたPowerShellセッション内で次のようにします:
Get-GpoReport -Domain example.com -All -ReportType xml -Path C:\temp\gporeport.xml
簡単です。
Grouperが動作するために必要なのはPowerShell 2.0とGet-GPOReportから出力されたXMLファイルだけです。心配なら、ネットワークカードなしのVMで実行しても問題なく動作します。
とはいえ、コードは非常に基本的なので、何か怪しいことをしているかどうかは簡単に確認できるはずです。
短い答え:その通りです。
長い答え:その通りで、どちらかの方法の方が良いでしょうが、まだそれを行うのを妨げるいくつかの理由があります。
理想的にはSYSVOLから直接ポリシーファイルを解析したいところですが、それらはさまざまなファイル形式で保存されており、一部はプロプライエタリで、読み取りが非常に面倒です。Microsoftが既に非常にうまく機能するコマンドレットを提供しているのに、それらのパーサーをゼロから書く時間も気力もありません。
遠くない将来に、MicrosoftのGet-GPOReportをGrouperに組み込んで、RSATを必要としないようにしたいと考えていますが、それが著作権侵害になるかどうかを確認する必要があります。また、その方法を実際に理解する必要もあります。
Grouperは脆弱性スキャナーではありません。Grouperは単にグループポリシーレポート内の膨大なノイズをフィルタリングし、悪用可能な方法で構成される可能性があるポリシー設定のみを表示します。
可能な限り、各チェックカテゴリに対して、明らかに脆弱でない構成を除去し、ノイズレベルをさらに低減するための追加フィルタリングを追加していますが、グループポリシーは非常に柔軟であり、管理者が犯す可能性のあるすべてのミスを予測することは非常に困難です。
良いですね。Grouperを改善する方法を見つけたということです!下にスクロールすると、Grouperに新しいチェックを追加するための簡単なガイドがあります。
任せてください。リポジトリにtest_report.xmlがあるので、試してみてください。これには多数の悪い設定が含まれているので、どのような出力になるか確認できます。
あまりにもひどい構成だらけで、ラボ環境でもGPOを有効にしたくなかったため、-showDisabledフラグを付けて実行する必要があります。
わかりました。

短い答え:PowerViewを使えばこれがうまくできます。
長い答え:いずれこの機能を追加しようとしていますが、それまでは黙ってPowerViewを使ってください。
簡単に修正できます。
grouper.ps1を開き、"$polchecks"配列を見つけて、そのチェックが配列に追加される行をコメントアウトしてください。
完了です。
もちろん、そうしましょう。
Grouperに検出させたいポリシー/設定の種類を含むGPOReport XML出力を取得します。これには、ラボ環境で適切なポリシーを作成する必要があるかもしれません。
対象のポリシーに一致する<GPO> XMLオブジェクトを見つけます。
ポリシーから抽出したい情報に一致するXMLのサブセクションを見つけます。ポリシー設定は通常、ユーザーまたはコンピューターポリシーに分かれているため、通常は以下のいずれかになります:
GPO.Computer.ExtensionData.Extension
または
GPO.User.ExtensionData.Extension
ここが厄介な部分です。このコードが混乱している理由は、各ポリシー設定セクションの構造が異なり、命名規則も大きく異なるため、対象ポリシーの構造を理解する必要があるからです。幸運を祈ります。
以下は、始めるために使用できるチェック関数のスケルトンです。何も見つからなかった場合は、何も返さないか、$nullを返すようにしてください。
Function Get-GPOThing {
[cmdletbinding()]
Param (
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] [System.Xml.XmlElement]$polXML,
[Parameter(Mandatory=$true)][ValidateSet(1,2,3)][int]$level
)
######
# Description: Checks for Things.
# Vulnerable: Description of what it shows if Level -eq 3
# Interesting: Description of what it shows if Level -eq 2
# Boring: All Things.
######
$settingsThings = ($polXml.Thing.ExtensionData.Extension.Thing | Sort-Object GPOSettingOrder)
if ($settingsThings) {
foreach ($setting in $settingsThings) {
if ($level -eq 1) {
$output = @{}
$output.Add("Name", $setting.Name)
if ($setting.SettingBoolean) {
$output.Add("SettingBoolean", $setting.SettingBoolean)
}
if ($setting.SettingNumber) {
$output.Add("SettingNumber", $setting.SettingNumber)
}
$output.Add("Type", $setting.Type.InnerText)
Write-Output $output
""
}
}
}
}
以下の方々に多大なる感謝を:
ひどいコードといえば、これがかなり乱雑であることは承知しています。可能な限りモジュール化して、他の人がそれほど手間をかけずに追加のチェックを追加できるようにしようとしましたが、まだまだ改善が必要です。修正が必要な間違いを見つけた場合は、ぜひ教えてください。
Ctrl+f で "$polchecks" まで移動し、他のチェックと一緒に配列に追加します。
テストします。
うまくいけば、プルリクエストを送信してください!
行き詰まったら、連絡してください。数分の時間を捻出できれば、手助けできるかもしれません。