一覧OP-02-3 · Windows認証・権限の記録

アカウントとグループの変更履歴

CORP/tempに関する変更と認証失敗を検索し、作成者、所属先、ロック前後の状態コードを確認します。失敗の件数だけで攻撃と断定せず、ロック後の失敗を別に数える流れを学びます。

説明

アカウントの監査では、操作した主体と変更された対象を分けて読みます。4720は作成、4728はセキュリティが有効なグローバルグループへの追加、4740はロックアウト、4767はロック解除です。

CORP/tempに関する変更と認証失敗を検索し、作成者、所属先、ロック前後の状態コードを確認します。失敗の件数だけで攻撃と断定せず、ロック後の失敗を別に数える流れを学びます。

1対象アカウントの記録を並べる

actorは操作主体、targetは対象です。認証失敗では操作主体を取得できないため「-」にしています。

from oplab import * db=connect(2) show(db, 'SELECT対象アカウントの記録を並べる * FROM changes WHERE target="CORP/temp" ORDER BY t')

admin、SYSTEM、helpdeskという複数の主体が現れます。対象アカウントの名前を変更主体と読み替えないようにします。

2作成と所属変更を確認する

作成されたことと、権限を与えるグループへ加えられたことを分けます。

show(db, 'SELECT作成と所属変更を確認する id,event,actor,target,detail FROM changes WHERE event IN (4720,4728)')

c1の作成後、c2でOpsへ追加されています。グループ名だけから管理者権限の全範囲までは分からず、グループに付く権限の確認が必要です。

3失敗コードごとに数える

同じ4625でもパスワード不一致とロック中では状態が異なります。

show(db, 'SELECT失敗コードごとに数える detail,COUNT(*) AS failures FROM changes WHERE event=4625 GROUP BY detail ORDER BY detail')

0xC000006Aは2件、0xC0000234は1件です。後者をパスワードの推測回数として加算すると意味が変わります。

4ロック前の失敗を抽出する

対象と時刻を条件にして、ロック以前に観測した失敗を表示します。

show(db, 'SELECTロック前の失敗を抽出する f.id,f.t,f.detail FROM changes f JOIN changes l ON f.target=l.target WHERE f.event=4625 AND l.event=4740 AND f.t<l.t ORDER BY f.t')

この試料で確認できる前段の失敗は2件です。収集済みの2件だけから、ドメイン全体のロック閾値が2回だったと断定はできません。

5呼出元と解除者を確認する

ロックイベントのCallerComputerNameと、解除イベントの主体を読みます。

show(db, 'SELECT呼出元と解除者を確認する id,t,event,actor,detail FROM changes WHERE event IN (4740,4767) ORDER BY t')

呼出元はws9、解除者はhelpdeskです。ws9上の保存済み資格情報や定期処理も調査候補になります。

6ロック期間中の失敗を抽出する

ロック時刻を含み、解除時刻を含まない区間で検索します。

show(db, 'SELECTロック期間中の失敗を抽出する f.id,f.detail FROM changes f JOIN changes l ON f.target=l.target JOIN changes u ON f.target=u.target WHERE f.event=4625 AND l.event=4740 AND u.event=4767 AND f.t>=l.t AND f.t<u.t')

c6はロック期間内の失敗です。作成、所属変更、認証失敗、ロック、解除を別の事実として説明できます。

まとめ

c6はロック期間内の失敗です。作成、所属変更、認証失敗、ロック、解除を別の事実として説明できます。

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

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

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

1
from oplab import * db=connect(2) show(db, 'SELECT * FROM changes WHERE target="CORP/temp" ORDER BY t')
id | t | event | actor | target | detail
c1 | 1 | 4720 | CORP/admin | CORP/temp | created
c2 | 3 | 4728 | CORP/admin | CORP/temp | Ops global group
c3 | 7 | 4625 | - | CORP/temp | 0xC000006A
c4 | 8 | 4625 | - | CORP/temp | 0xC000006A
c5 | 9 | 4740 | SYSTEM | CORP/temp | CallerComputerName=ws9
c6 | 10 | 4625 | - | CORP/temp | 0xC0000234
c7 | 12 | 4767 | CORP/helpdesk | CORP/temp | unlocked
2
show(db, 'SELECT id,event,actor,target,detail FROM changes WHERE event IN (4720,4728)')
id | event | actor | target | detail
c1 | 4720 | CORP/admin | CORP/temp | created
c2 | 4728 | CORP/admin | CORP/temp | Ops global group
3
show(db, 'SELECT detail,COUNT(*) AS failures FROM changes WHERE event=4625 GROUP BY detail ORDER BY detail')
detail | failures
0xC000006A | 2
0xC0000234 | 1
4
show(db, 'SELECT f.id,f.t,f.detail FROM changes f JOIN changes l ON f.target=l.target WHERE f.event=4625 AND l.event=4740 AND f.t<l.t ORDER BY f.t')
id | t | detail
c3 | 7 | 0xC000006A
c4 | 8 | 0xC000006A
5
show(db, 'SELECT id,t,event,actor,detail FROM changes WHERE event IN (4740,4767) ORDER BY t')
id | t | event | actor | detail
c5 | 9 | 4740 | SYSTEM | CallerComputerName=ws9
c7 | 12 | 4767 | CORP/helpdesk | unlocked
6
show(db, 'SELECT f.id,f.detail FROM changes f JOIN changes l ON f.target=l.target JOIN changes u ON f.target=u.target WHERE f.event=4625 AND l.event=4740 AND u.event=4767 AND f.t>=l.t AND f.t<u.t')
id | detail
c6 | 0xC0000234

演習完了