EDRによる端末の活動の検索
端末、中央記録、対応処理を照合し、記録から言える範囲を判断します。
説明
単独のファイル作成や接続は通常の作業でも発生します。複数イベントの組合せを条件にすると、調べる対象を絞れますが、正当な作業も条件に一致し得ます。
同じプロセスがファイルを作った後に接続した組を検索します。時間幅と識別子を変え、誤った結合や遅延取込の影響を確認します。
端末、中央記録、対応処理を照合し、記録から言える範囲を判断します。
1ファイルと接続の時刻を並べる
対象はファイル作成後の外向き接続です。
from sp02 import *
db = connect()
showファイルと接続の時刻を並べる(db,"SELECT host,t,kind,guid FROM event WHERE kind IN ('file','network') ORDER BY t")ws8の接続は3秒、ws7のファイル作成は4秒、ws7の接続は8秒です。
2端末とプロセスをそろえて結合する
作成から5秒以内の接続を検索します。
query = "SELECT f.record AS file_id,n.record AS net_id,n.t-f.t AS seconds FROM event f JOIN event n ON f.host=n.host AND f.guid=n.guid WHERE f.kind='file' AND n.kind='network' AND n.t-f.t BETWEEN 0 AND ?"
show端末とプロセスをそろえて結合する(db,query,(5,))記録2と3が4秒差で一致します。判定の根拠をイベントIDで残すと後から原記録に戻れます。
3時間幅を短くする
許容幅を3秒へ変えます。
show時間幅を短くする(db,query,(3,))一致がなくなります。閾値を下げると通知が減りますが、同じ活動を見落とす場合があります。
4順序を逆にした組を確認する
接続後のファイル作成を同じ5秒幅で検索します。
show順序を逆にした組を確認する(db,"SELECT n.record,f.record,f.t-n.t AS seconds FROM event n JOIN event f ON n.host=f.host AND n.guid=f.guid WHERE n.kind='network' AND f.kind='file' AND f.t-n.t BETWEEN 0 AND 5")今回のg1では逆順の組がありません。時間差の絶対値だけで検索すると、手順の前後を失います。
5PIDだけで結合した場合を比較する
同じPIDであれば端末が違っても結び付ける検索です。
showPIDだけで結合した場合を比較する(db,"SELECT f.host,n.host,n.t-f.t AS seconds FROM event f JOIN event n USING(pid) WHERE f.kind='file' AND n.kind='network' ORDER BY n.t")別端末との組と負の時間差が混ざります。検知条件より前に、同じ主体を結ぶキーを確かめます。
6遅れて届いた記録の待ち時間を求める
記録2と3の両方が中央で利用できる最初の時点を計算します。
show遅れて届いた記録の待ち時間を求める(db,"SELECT MAX(ingested) AS available_at,MAX(ingested)-MAX(t) AS after_last_event FROM event WHERE record IN (2,3)")20秒に両方がそろいます。最後の活動から12秒後なので、この中央検索は実行前の防止ではありません。
7通知時点より前に起きたことを確認する
通知を20秒に作ったとき、既に終わった活動を列挙します。
show通知時点より前に起きたことを確認する(db,"SELECT t,kind,detail FROM event WHERE guid='g1' AND t<20 ORDER BY t")ファイル作成と接続は既に発生しています。実行後に検知したという記録から、過去の処理まで取り消されたとは判断できません。
まとめ
相関条件には主体、順序、時間幅を含めます。
検索の根拠となったイベントIDを保持します。
検知時刻と防止できた時点を混同しません。
操作履歴と解説を振り返れます。
Python 3.15 / SQLite / 固定の端末記録
from sp02 import *
db = connect()
show(db,"SELECT host,t,kind,guid FROM event WHERE kind IN ('file','network') ORDER BY t")host | t | kind | guid ws8 | 3 | network | g3 ws7 | 4 | file | g1 ws7 | 8 | network | g1
query = "SELECT f.record AS file_id,n.record AS net_id,n.t-f.t AS seconds FROM event f JOIN event n ON f.host=n.host AND f.guid=n.guid WHERE f.kind='file' AND n.kind='network' AND n.t-f.t BETWEEN 0 AND ?"
show(db,query,(5,))file_id | net_id | seconds 2 | 3 | 4
show(db,query,(3,))file_id | net_id | seconds
show(db,"SELECT n.record,f.record,f.t-n.t AS seconds FROM event n JOIN event f ON n.host=f.host AND n.guid=f.guid WHERE n.kind='network' AND f.kind='file' AND f.t-n.t BETWEEN 0 AND 5")record | record | seconds
show(db,"SELECT f.host,n.host,n.t-f.t AS seconds FROM event f JOIN event n USING(pid) WHERE f.kind='file' AND n.kind='network' ORDER BY n.t")host | host | seconds ws7 | ws8 | -1 ws7 | ws7 | 4
show(db,"SELECT MAX(ingested) AS available_at,MAX(ingested)-MAX(t) AS after_last_event FROM event WHERE record IN (2,3)")available_at | after_last_event 20 | 12
show(db,"SELECT t,kind,detail FROM event WHERE guid='g1' AND t<20 ORDER BY t")t | kind | detail 0 | process | start 4 | file | report.txt 8 | network | 192.0.2.20:443
演習完了