Windows 2000 ServerをWindows Server 2008に移行するにあたって、変わったところは機能だけではない。この10年ぐらいの間にお客さんのセキュリティに対する知識が高くなっている。そのこと自体はいいことなんだけど、単純移行という理由で費用を削られているのに、セキュリティ対策については、やるのが当たり前のようになっているから達が悪い。

セキュリティでよく言われるのが重要データへのアクセスをログに記録してほしいということ。ここではWindows の標準機能を使って重要データへのアクセスを記録し監査を行う方法までを記す。

【監査ポリシーの設定】
サーバ上のファイル操作について監査を行うためには、まず監査ポリシーの設定を行い、オブジェクトアクセス、及びログオンの成功/失敗をセキュリティログに出力するように設定する必要がある。

監査ポリシーの設定は、Active Directoryのグループポリシーもしくは、ローカルセキュリティポリシーから設定を行うことができる。

「管理ツール」→「ローカルセキュリティポリシー」を起動し、「セキュリティの設定」→「ローカルポリシー」と展開し、「監査ポリシー」を選択する。右側 のポリシーより、「アカウントログオンイベント監査」「オブジェクトアクセスの監査」「ログオンイベントの監査」の成功/失敗を監査できるように設定す る。

【監査エントリの追加】
監査ポリシーの設定のみでは監査ログは出力されない。監査ログを出力するために、監査対象となるファイルまたはディレクトリに対し、監査エントリを追加す る。
監査エントリの追加は、エクスプローラより監査対象となるファイルまたはフォルダを右クリックし、「プロパティ」を選択する。

プロパティが開いたら「セキュリティ」タブに移動し、「詳細設定」をクリックする。

「セキュリティの詳細設定」が開いたら「監査」タブに移動し、「追加」をクリックする。

「ユーザ、コンピュータまたはグループの選択」が開いたら、「Everyone」と入力して「OK」をクリックする。

「監査」エントリが開いたら「アクセス」より、以下の項目の成功と失敗にチェックする。
・フォルダの一覧/データの読み取り 成功・失敗
・ファイルの作成/データの書き込み 成功・失敗
・フォルダの作成/データの追加 成功・失敗
・サブフォルダとファイルの削除 成功・失敗
・削除 成功・失敗
・所有権の取得 成功・失敗

「OK」をクリックし、監査エントリの追加を終了する。

【監査方法】
ここまでの設定を行うとセキュリティログがイベントログに出力されるようになる。イベントログに出力されたセキュリティログよりファイル操作の監査を行にはイベントID4663と4624を確認する。※イベントID4663と4624の紐付けは「全般」にある「ログオン ID」が一致するかどうかで行う。

イベントID4663より確認できる情報は以下の通り。

・いつファイルへのアクセスが行われたのか
イベントログの「日付」「時刻」から確認できる。

・どのような操作が行われたのか
イベントログの「全般」にある「アクセス要求情報-アクセス」から確認できる。

・どのようなアプリケーションから操作が行われたのか
イベントログの「全般」にある「プロセス情報-プロセス」から確認できる。

イベントID4624より確認できる情報は以下の通り。

・どのクライアントから操作を行ったのか
イベントログの「全般」にある「ネットワーク情報」から確認できる。

セキュリティログは大量に出力されるため目視による確認は難しい。PowerShell等でツールを作成すると便利になる。
下記のスクリプトは、イベントID4663と4626を結合し、ファイル操作の監査に必要な項目をCSVファイルに出力する機能を持つ。

【実行方法】
PowerShell -NoProfile -File ".\AuditLog.ps1" > sec.csv

--- AuditLog.ps1 ---------------------------------------------------
#requires -version 2.0

function GetValue([String]$category, [String]$key, [String[]]$properties)
{
  $b = $false;
  foreach ($property in $properties) {
    if ($b -eq $false) {
      if ($property.contains($category)) {
        $b = $true;
        continue;
      }
    } else {
      if ($property.contains($key)) {
        return [String]$property.Substring($property.IndexOf(":")+1).Trim();
      }
    }
  }
  return "";
}

function ConvertACL([string]$accessList)
{
  switch ($accessList.trim()) {
  "%%1537" { return "Delete"; }
  "%%1538" { return "Read_CONTROL"; }
  "%%1539" { return "Write_DAC"; }
  "%%1540" { return "Write_OWNER"; }
  "%%1541" { return "Synchronize"; }
  "%%4416" { return "ReadData (or List Directory)"; }
  "%%4417" { return "WriteData (or Add File)"; }
  "%%4418" { return "AppendData (or AddSubdirectory or CreatePipeInstance)"; }
  "%%4419" { return "ReadEA"; }
  "%%4420" { return "WriteEA"; }
  "%%4421" { return "ExecuteFile"; }
  "%%4422" { return "DeleteChild"; }
  "%%4423" { return "ReadAttributes"; }
  "%%4424" { return "WriteAttributes"; }
  default { return "Other"; }
  }
}

function GetLogonInfo([String]$logonid, [Object[]]$entrys)
{
  foreach ($entry in $entrys) {
    $properties = $entry.Message.Split("`n");
    #ID4663のログオンIDとID4624のログオンIDが一致するかどうか
    if ($logonid -eq (GetValue "新しいログオン:" "ログオン ID:" $properties)) {
      return (GetValue "ネットワーク情報:" "ワークステーション名:" $properties), `
          (GetValue "ネットワーク情報:" "ソース ネットワーク アドレス:" $properties);
    }
  }
  return "","";
}

#初期エントリポイント

$logons =  Get-EventLog Security | Where-Object { $_.EventID -eq '4624' };
$acslogs = Get-EventLog Security | Where-Object { $_.EventID -eq '4663' };
$i = 0;

Write-Output "日時,ユーザ名,ドメイン名,コンピュータ名,IPアドレス,ファイル名,操作,アプリケーション";

foreach ($entry in $acslogs) {
  $i = $i + 1;
  Write-Progress -Activity "Outputting Event" `
    -Status "Progress:" -PercentComplete ($i/$acslogs.count*100);

  $properties = $entry.Message.Split("`n");
  $csv = [String]$entry.TimeGenerated.ToString("yyyy/MM/dd HH:mm:ss");
  $csv = $csv+","+(GetValue "サブジェクト:" "アカウント名:" $properties);
  $csv = $csv+","+(GetValue "サブジェクト:" "アカウント ドメイン:" $properties);
  $logoninfo = (GetLogonInfo (GetValue "サブジェクト:" "ログオン ID:" $properties) $logons);
  $csv = $csv+","+($logoninfo[0]); #ワークステーション名
  $csv = $csv+","+($logoninfo[1]); #ソースネットワークアドレス
  $csv = $csv+","+(GetValue "オブジェクト:" "オブジェクト名:" $properties);
  $csv = $csv+","+(ConvertACL((GetValue "アクセス要求情報:" "アクセス:" $properties)));
  $csv = $csv+","+(GetValue "プロセス情報:" "プロセス名:" $properties);

  Write-Output $csv;
}

exit 0;