一覧SP-02-2 · EDR:端末の観測・検知・対応

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 / 固定の端末記録

1
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
2
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
3
show(db,query,(3,))
file_id | net_id | seconds
4
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
5
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
6
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
7
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

演習完了