一覧OP-03-3 · Windowsプロセス・永続化の記録

PowerShellログの復元と収集範囲

固定のスクリプトブロック断片を並べ、完成した内容と欠けた内容を分けます。WMIの記録や収集設定も調べ、文字列が記録されたこと、処理が成功したこと、ログが残る条件を別々に評価します。

説明

PowerShellのスクリプトブロック記録は一つの内容が複数のイベントへ分割されることがあります。部分番号と総数を確認してから結合しないと、処理の一部を読み落とします。

固定のスクリプトブロック断片を並べ、完成した内容と欠けた内容を分けます。WMIの記録や収集設定も調べ、文字列が記録されたこと、処理が成功したこと、ログが残る条件を別々に評価します。

1断片番号を読む

blockはScriptBlockId、partとtotalは分割番号と総数に相当する抽出列です。

from oplab import * db=connect(3) show(db, 'SELECT断片番号を読む id,block,part,total,text FROM script WHERE block IS NOT NULL ORDER BY block,part')

sb7は1/2と2/2があり、sb8は1/2だけです。同じブロックの断片を順序付きで扱います。

2欠けているブロックを見つける

重複した配送があっても充足と誤認しないよう、異なる部分番号を数えます。

show(db, 'SELECT欠けているブロックを見つける block,COUNT(DISTINCT part) AS parts,MAX(total) AS expected FROM script WHERE block IS NOT NULL GROUP BY block')

sb7は2/2、sb8は1/2です。総数が一致するかに加え、番号の範囲や総数の不一致も本来の検査対象です。

3順番どおりに本文を復元する

並び順を指定した副問い合わせからgroup_concatへ渡します。

show(db, 'SELECT順番どおりに本文を復元する group_concat(text,"") AS script_text FROM (SELECT text FROM script WHERE block="sb7" ORDER BY part)')

Get-Content C:/Data/report.txtになります。スクリプト内容の記録だけでは、読み出しが成功したか、出力がどこへ届いたかは分かりません。

4WMI側の観測を確認する

WMIの操作記録には、呼出元プロセスや結果コードが含まれる場合があります。

show(db, 'SELECTWMI側の観測を確認する id,t,text FROM script WHERE channel="WMI-Activity/Operational"')

w1にはClientProcessId=500があります。PID再利用を考え、端末と時刻を合わせずに別記録へ結び付けないようにします。

5監査が有効だった期間を調べる

開始を含み終了を含まない区間として収集設定を記録しています。

show(db, 'SELECT監査が有効だった期間を調べる * FROM coverage ORDER BY channel,start')

PowerShellは時刻10から、WMIは15からが対象です。それ以前に検索結果がないことは、活動がなかった証拠になりません。

6不完全な本文を抽出する

完全な内容として扱えないブロックを調査課題として残します。

show(db, 'SELECT不完全な本文を抽出する block FROM script WHERE block IS NOT NULL GROUP BY block HAVING COUNT(DISTINCT part)<>MAX(total)')

sb8は追加取得が必要です。復元できた文字列、実行結果、未収集の範囲を一つの確実な結論へまとめないようにします。

まとめ

sb8は追加取得が必要です。復元できた文字列、実行結果、未収集の範囲を一つの確実な結論へまとめないようにします。

表示された証拠IDと検索条件を残すと、調査結果を元の記録までたどれます。

操作履歴と解説を振り返れます。

Python 3.15 / SQLite・固定の調査記録

1
from oplab import * db=connect(3) show(db, 'SELECT id,block,part,total,text FROM script WHERE block IS NOT NULL ORDER BY block,part')
id | block | part | total | text
b1 | sb7 | 1 | 2 | Get-Content 
b2 | sb7 | 2 | 2 | C:/Data/report.txt
b3 | sb8 | 1 | 2 | Get-Item 
2
show(db, 'SELECT block,COUNT(DISTINCT part) AS parts,MAX(total) AS expected FROM script WHERE block IS NOT NULL GROUP BY block')
block | parts | expected
sb7 | 2 | 2
sb8 | 1 | 2
3
show(db, 'SELECT group_concat(text,"") AS script_text FROM (SELECT text FROM script WHERE block="sb7" ORDER BY part)')
script_text
Get-Content C:/Data/report.txt
4
show(db, 'SELECT id,t,text FROM script WHERE channel="WMI-Activity/Operational"')
id | t | text
w1 | 18 | ClientProcessId=500; ResultCode=0x0
5
show(db, 'SELECT * FROM coverage ORDER BY channel,start')
channel | start | end | enabled
PowerShell/Operational | 0 | 10 | 0
PowerShell/Operational | 10 | 30 | 1
WMI-Activity/Operational | 15 | 30 | 1
6
show(db, 'SELECT block FROM script WHERE block IS NOT NULL GROUP BY block HAVING COUNT(DISTINCT part)<>MAX(total)')
block
sb8

演習完了