【極限の防御】VBScriptによるファイル生成レート監視と自動隔離ロジックの設計思想
業務自動化エンジニアとして現場に立つ君たちに、まず問いたい。
「君が書いたスクリプトは、想定外の事態に対して『沈黙』するか、それとも『抵抗』するか?」
単にファイルをコピーし、データを集計する。それだけが自動化の仕事ではない。プロフェッショナルが作成するツールには、「システムの健全性を守るための自己防衛ロジック」が組み込まれていなければならない。
特に、ランサムウェアのような挙動(短時間での大量のファイル生成・書き換え)が発生した場合、不完全なスクリプトは被害を拡大させるだけの「無力な道具」に成り下がる。本記事では、FileSystemObject (FSO) を極限まで制御し、異常なファイル生成レートを検知して対象ディレクトリを即座に「ロックダウン(隔離)」する、堅牢な防衛ロジックの設計思想と実装を伝授する。
1. 設計思想:なぜ「単純なループ」では通用しないのか
多くの初級者は、フォルダ内のファイルを一つずつチェックするループを書き、その中で「作成日時」を判定しようとする。それは致命的な設計ミスだ。
ファイル数が数千、数万と増えた瞬間、その $O(n)$ の走査はCPUリソースを食いつぶし、監視ツール自体のレスポンスを低下させる。攻撃者がその隙を見逃すはずがない。
我々が採用すべきは、「統計的デルタ(差分)監視」である。
個々のファイルの中身を見るのではなく、「一定時間内におけるファイル総数の変化量(Velocity)」を監視する。これにより、計算量を最小限に抑えつつ、異常な書き込み速度を数学的に捉えることが可能になる。
防衛戦略の3原則
1. 低オーバーヘッド監視: ファイル個別の属性ではなく、フォルダの `Files.Count` プロパティを主軸に監視する。
2. 即時隔離 (Isolation): 異常検知時、削除ではなく「属性変更(Read-Only化)」および「パスの移動」を行う。削除は証拠隠滅に繋がるが、隔離はフォレンジック(事後解析)を可能にする。
3. 例外処理の徹底: ファイルロックやアクセス拒否(Access Denied)が発生しても、監視プロセス自体を死なせない。
2. プロダクション・コード:自己防衛型監視エンジン
以下に、実務でそのまま利用可能なレベルまで昇華させたコードを示す。
このコードは、単なるサンプルではない。エラーハンドリング、オブジェクトの解放、リソース管理を徹底した「動くプロトタイプ」だ。
'**
' Script Name: SelfDefendingMonitor.vbs
' Description: ファイル生成レートを監視し、異常検知時にフォルダを隔離する
' Author: Chief Architect
'**
Option Explicit
' --- 設定領域 (Configuration) ---
Const TARGET_DIR = "C:\Work\CriticalData" ' 監視対象フォルダ
Const QUARANTINE_DIR = "C:\Work\Quarantine" ' 隔離先フォルダ
Const THRESHOLD_COUNT = 50 ' 検知閾値(一定期間内の生成ファイル数)
Const CHECK_INTERVAL = 5000 ' 監視間隔 (ミリ秒) 5秒
Const LOG_FILE = "C:\Work\monitor_log.txt"
' --- グローバル変数 ---
Dim objFSO, objTargetFolder, objQuarantineFolder
Dim prevFileCount, currentFileCount, deltaCount
Dim isLockedDown
'------------------------------------------------------------------------------
' メインエントリーポイント
'------------------------------------------------------------------------------
Sub Main()
Set objFSO = CreateObject("Scripting.FileSystemObject")
' 初期チェック
If Not objFSO.FolderExists(TARGET_DIR) Then
LogError "Target directory does not exist: " & TARGET_DIR
WScript.Quit 1
End If
If Not objFSO.FolderExists(QUARANTINE_DIR) Then
objFSO.CreateFolder(QUARANTINE_DIR)
End If
LogInfo "Monitoring started on: " & TARGET_DIR
prevFileCount = objFSO.GetFolder(TARGET_DIR).Files.Count
isLockedDown = False
' 監視ループ
Do While Not isLockedDown
WScript.Sleep CHECK_INTERVAL
MonitorLoop
Loop
LogInfo "Monitor stopped. System is in Lockdown mode."
End Sub
'------------------------------------------------------------------------------
' 監視ロジック
'------------------------------------------------------------------------------
Sub MonitorLoop()
On Error Resume Next ' 実行時エラーによるプロセス停止を防止
Set objTargetFolder = objFSO.GetFolder(TARGET_DIR)
currentFileCount = objTargetFolder.Files.Count
' エラーチェック (アクセス拒否など)
If Err.Number <> 0 Then
LogError "Error accessing folder: " & Err.Description
Err.Clear
Exit Sub
End If
' 差分計算
deltaCount = currentFileCount - prevFileCount
' 異常検知 (閾値を超えた場合)
If deltaCount >= THRESHOLD_COUNT Then
LogInfo "!!! ALERT: Abnormal file creation detected (" & deltaCount & " files) !!!"
ExecuteLockdown
Else
' 正常時はカウントを更新
prevFileCount = currentFileCount
End If
On Error GoTo 0
End Sub
'------------------------------------------------------------------------------
' 緊急隔離プロセス (Lockdown)
'------------------------------------------------------------------------------
Sub ExecuteLockdown()
LogInfo "Executing Lockdown Protocol..."
On Error Resume Next
' 1. フォルダ属性を読み取り専用に変更(これだけでは不十分だが、一次防衛として)
' ※注意: フォルダ自体への書き込み制限はOSの権限に依存する
' 2. フォルダを隔離ディレクトリへ移動(これが最も強力な隔離)
Dim newPath
newPath = QUARANTINE_DIR & "\Locked_" & Replace(TARGET_DIR, ":", "_") & "_" & Timer
' フォルダの移動を試みる
' ※ファイルが使用中の場合はエラーになるため、エラーハンドリングが重要
objFSO.MoveFolder TARGET_DIR, newPath
If Err.Number <> 0 Then
LogError "Lockdown failed! Files might be in use. Attempting attribute lockdown..."
' 移動に失敗した場合、フォルダ内の全ファイルにReadOnly属性を付与して時間を稼ぐ
Dim file
For Each file In objTargetFolder.Files
file.ReadOnly = True
Next
' 移動失敗時は、ループを抜けて監視を止める(被害拡大を防ぐため)
isLockedDown = True
Else
LogInfo "Success: Target folder moved to " & newPath
isLockedDown = True
End If
If Err.Number <> 0 Then Err.Clear
On Error GoTo 0
End Sub
'------------------------------------------------------------------------------
' ユーティリティ (Logging)
'------------------------------------------------------------------------------
Sub LogInfo(msg)
WriteLog "INFO", msg
End Sub
Sub LogError(msg)
WriteLog "ERROR", msg
End Sub
Sub WriteLog(level, msg)
Dim ts, objLog
ts = Now
msg = "[" & ts & "] [" & level & "] " & msg
' コンソール出力
WScript.Echo msg
' ファイル出力
On Error Resume Next
Set objLog = objFSO.OpenTextFile(LOG_FILE, 8, True) ' 8 = ForAppending
objLog.WriteLine msg
objLog.Close
On Error GoTo 0
End Sub
'------------------------------------------------------------------------------
' スクリプト実行
'------------------------------------------------------------------------------
Main
3. 実務における「堅牢な設計」の急所
このコードをそのままコピペして動かすだけでは、一流とは言えない。運用に投入する前に、以下の3点を必ず検討せよ。
① 偽陽性 (False Positive) への対策
大量のファイル生成は、必ずしも攻撃とは限らない。例えば、バックアップソフトの動作や、ログローテーション、ビルドプロセスがこれに該当する。
- 対策: `THRESHOLD_COUNT` を「業務上の最大書き込み量」の1.5倍〜2倍に設定すること。また、特定のプロセスによる書き込みを無視するホワイトリスト機能(ファイル名のパターンマッチング)を追加することを検討せよ。
② ファイルロックの壁
ランサムウェアがファイルを暗号化している最中は、そのファイルは「使用中」となり、FSOによる移動や属性変更が `Access Denied (0x80070005)` で失敗する。
- 設計の勘所: `ExecuteLockdown` 内で、移動に失敗した際の「フォールバック(代替策)」を記述している点に注目せよ。移動ができなければ、可能な限り属性変更(ReadOnly化)を試みる。これが「粘り強い設計」だ。
③ オブジェクトのライフサイクル管理
VBScriptにおいて、`Set obj = Nothing` を忘れることは、メモリリークの種をまくことに等しい。特に監視ループのような長時間稼働するスクリプトでは、ループ内でオブジェクトを生成・破棄する場合、確実に解放しなければならない。本コードでは、ループの外でオブジェクトを生成し、再利用することでパフォーマンスを最適化している。
結論
自動化エンジニアの真価は、「動くものを作る能力」ではなく、「壊れたとき、あるいは攻撃を受けたときに、システムをどう制御するか」という設計思想に宿る。
FSOは強力な武器だが、制御を誤れば自らのシステムを破壊する凶器にもなり得る。常に「最悪のシナリオ」を想定し、ロジカルで堅牢なコードを書き上げろ。
以上だ。健闘を祈る。
