【実務・中級編】【ファイル共有アクセス権の動的検証】WMI (Win32_LogicalShareSecuritySetting) によるフォルダ共有パーミッション調査 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【ファイル共有アクセス権の動的検証】WMI (Win32_LogicalShareSecuritySetting) によるフォルダ共有パーミッション調査

開発現場やインフラ運用において、ネットワーク共有フォルダのセキュリティ管理ほど頭痛の種になるものはない。
「誰がどのフォルダにアクセスできるのか?」
この問いに対して、GUIのプロパティ画面を一つずつポチポチと確認して回るような前時代的な手法をとっている現場があるならば、今すぐその手を止めてほしい。それはエンジニアの仕事ではなく、ただの苦行だ。

我々はプログラマーであり、自動化のスペシャリストだ。数十、数百ある共有フォルダのACL(アクセス制御リスト)やDACLを動的に抽出し、セキュリティホールを自動で炙り出す仕組みこそが求められている。

今回は、VBScriptとWMI(Windows Management Instrumentation)の深淵を覗き、`Win32_LogicalShareSecuritySetting` を駆使してファイル共有のアクセス権を完全解読・監査するプロダクションコードを伝授する。

なぜPowerShell全盛期にVBScriptなのか?

「おいおい、今どきVBScriptかよ。PowerShellがあるだろ」というツアラーの声が聞こえてくる。
だが、待ってほしい。エンタープライズの現場、特にレガシーなWindows Server環境や、セキュリティポリシーがガチガチに固められていてPowerShellの実行ポリシー(ExecutionPolicy)すら変更できない踏み台サーバー、あるいはサードパーティ製ツールへの組み込みを余儀なくされる環境において、「OS標準で無条件に即座に動く」というVBScriptの特権的アドバンテージはいまだに失われていない。

余計なランタイムのインストールや、グループポリシーの書き換えを待つ必要はない。メモ帳さえあれば、数秒でインフラの急所を突く監査ツールをデプロイできる。この機動性こそがVBScriptの真骨頂なのだ。

アーキテクチャの核心:WMIとセキュリティ記述子の罠

今回ターゲットにするのは、WMIの以下の2つのクラスの連携だ。

1. `Win32_Share`: 共有名と物理パスの対応を取得する。
2. `Win32_LogicalShareSecuritySetting`: 共有に紐づくセキュリティ設定(DACL)を保持する。

ここで多くの初心者がハマる罠がある。`Win32_Share` から得られる情報には、実際の「誰が何ができるか」というアクセスの詳細が含まれていない。セキュリティ設定は、ASSOCIATORS OFクエリを用いて、セキュリティ記述子(Security Descriptor)を紐解く必要がある。

さらに、WMIが返すDACL(Discretionary Access Control List)は、バイナリやネストされたCOMオブジェクトの集合体(`Win32_SecurityDescriptor` -> `Dacl` -> `Win32_Trustee` / `AccessMask`)であり、これを適切にパースするには、VBScriptの動的型付けの特性を理解し、エラーハンドリングを網羅した堅牢なループ構造を組む必要がある。

プロダクションコード:共有権限自動監査スクリプト

以下のコードは、単に権限を表示するだけではない。ログファイル(CSV形式)に出力し、後続のExcel分析やデータベース連携にそのまま耐えうる設計にしている。

‘ ==============================================================================
‘ Script Name : Audit-SharePermissions.vbs
‘ Description : WMIを用いたネットワーク共有フォルダのアクセス権(ACL)動的監査
‘ Author : チーフアーキテクト
‘ ==============================================================================

Option Explicit

Dim objWMIService, colShares, objShare, colSecSettings, objSecSetting
Dim objSecurityDescriptor, objDacl, objTrustee
Dim fso, tsLog, logPath
Dim strComputer, i, accessType, accessString

‘ 1. 実行環境の初期化とログファイルの準備
strComputer = “.”
Set fso = CreateObject(“Scripting.FileSystemObject”)
logPath = fso.GetParentFolderName(WScript.ScriptFullName) & “\ShareAudit_Log_” & FormatDate(Now) & “.csv”
Set tsLog = fso.CreateTextFile(logPath, True)

‘ CSVヘッダーの書き込み
tsLog.WriteLine “ShareName,Path,Account,Domain,AccessType,AccessMask”

‘ 2. WMIサービスの接続 (CIMv2)
On Error Resume Next
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
If Err.Number <> 0 Then
WScript.Echo “[-] WMIへの接続に失敗しました: ” & Err.Description
WScript.Quit 1
End If
On Error GoTo 0

‘ 3. 共有フォルダの一覧を取得
Set colShares = objWMIService.ExecQuery(“SELECT FROM Win32_Share WHERE Type = 0”) ‘ Type 0 = ディスクドライブの共有

WScript.Echo “[+] 共有フォルダの監査を開始します…”

For Each objShare in colShares
‘ 4. 該当共有のセキュリティ設定をASSOCIATORS OFクエリで取得
Set colSecSettings = objWMIService.ExecQuery _
(“ASSOCIATORS OF {Win32_Share.Name='” & objShare.Name & “‘} ” & _
“WHERE AssocClass=Win32_LogicalShareSecuritySetting”)

For Each objSecSetting in colSecSettings
‘ セキュリティ記述子を取得
Dim oArgs(0)
oArgs(0) = Null

On Error Resume Next
Set objSecurityDescriptor = objSecSetting.GetSecurityDescriptor_().Descriptor

If Err.Number = 0 And Not IsNull(objSecurityDescriptor) Then
Set objDacl = objSecurityDescriptor.Dacl

If Not IsNull(objDacl) Then
For Each objTrustee in objDacl
‘ アクセス権の種別判定 (Allowed / Denied)
If objTrustee.AceType = 0 Then
accessType = “Allow”
ElseIf objTrustee.AceType = 1 Then
accessType = “Deny”
Else
accessType = “Other(” & objTrustee.AceType & “)”
End If

‘ CSVへ出力 (ShareName, Path, Account, Domain, AccessType, AccessMask)
tsLog.WriteLine “””” & objShare.Name & “””,””” & _
objShare.Path & “””,””” & _
objTrustee.Trustee.Name & “””,””” & _
objTrustee.Trustee.Domain & “””,””” & _
accessType & “””,””” & _
objTrustee.AccessMask & “”””
Next
End If
End If
On Error GoTo 0
Next
Next

tsLog.Close
WScript.Echo “[+] 監査が完了しました。出力先: ” & logPath

‘ — 補助関数: 日付の文字列フォーマット (YYYYMMDD_HHMMSS) —
Function FormatDate(dt)
Dim yyyy, mm, dd, hh, nn, ss
yyyy = CStr(Year(dt))
mm = Right(“0” & CStr(Month(dt)), 2)
dd = Right(“0” & CStr(Day(dt)), 2)
hh = Right(“0” & CStr(Hour(dt)), 2)
nn = Right(“0” & CStr(Minute(dt)), 2)
ss = Right(“0” & CStr(Second(dt)), 2)
FormatDate = yyyy & mm & dd & “_” & hh & nn & ss
End Function

このコードが「プロダクション品質」である理由

素人が書いたスクリプトと、プロが書くスクリプトの決定的な違いは「例外に対する強靭さ」「出力データの構造化」にある。

1. 厳格なエラーハンドリング (`On Error Resume Next` の正しい使い方)

WMIクエリやセキュリティ記述子の取得は、OSの権限不足やネットワークの瞬断、特殊なサードパーティ製ドライバの影響で予期せぬエラー(`Object variable not set`など)を吐きやすい。
ここでは、エラーが発生しうるブロックを最小限に絞り、`Err.Number` を確実に監視することで、1つの共有フォルダの異常終了がスクリプト全体をクラッシュさせるのを防いでいる。

2. ダブルクォーテーションのエスケープによるCSVインジェクション・パースエラーの防止

共有名やパス、ユーザー名にはスペースやカンマが含まれることが多々ある。適当にカンマ区切りで出力するとExcelで開いたときに列が盛大にズレる。
出力文字列を必ずダブルクォーテーション (`””””`) で囲むことで、CSVとしての整合性を完全に担保している。

3. アクセス権マスク(AccessMask)の保持

コード内では生の値(ビットマスク)である `AccessMask` をそのまま出力している。
フルコントロール(`2032127`)や読み取り(`1179817`)などのビット演算判定をVBScript側で無理に行うとコードが肥大化する。実務では、抽出したCSVをデータベースに流し込むか、Excel側のマクロやパワークエリで一括変換する方が、スクリプトの軽量性と保守性の観点から圧倒的にスマートである。

運用時の注意点とデータベース・ファイル連携への布石

1. 実行権限の要件
このスクリプトを走らせるアカウントは、当然ながら対象サーバーの「管理者権限(Administrator またはそれに準ずる権限)」を持っていなければならない。一般ユーザーで実行した場合、WMIのセキュリティ記述子取得部分でアクセス拒否が発生し、空のログが出力されることになる。

2. データベース(SQL Server / SQLite等)との連携
生成されたCSVファイルは、そのままRDBのステージングテーブルへBULK INSERTすることが可能だ。
「前回の監査結果」と「今回の監査結果」を比較する差分クエリ(DIFF)を走らせることで、「いつの間にか誰もがアクセスできる共有フォルダが作成されていた」という最悪のセキュリティインシデントを検知するアラートシステムへと昇華させることができる。

チーフアーキテクトからの総括

「手動で確認する」というコストは、組織がスケールすればするほど複利で増大していく。
今回紹介したWMIを用いた共有権限の動的検証は、単なる「サボるためのツール」ではなく、インフラのガバナンスを担保するためのである。

VBScriptという枯れた技術であっても、アーキテクチャを理解し、堅牢に組み上げれば、最前線で戦える強力な武器になる。ぜひ自身の環境にデプロイし、野良共有フォルダの存在を暴き出してほしい。

タイトルとURLをコピーしました