performing-user-behavior-analytics について
SOCチームや内部脅威対策向けに、過去の活動からユーザーの異常な行動を見つけるセキュリティスキルです。認証・アクセスのベースライン、異常検知、リスクスコアの集約を扱い、結果は断定ではなく調査の手掛かりとして扱います。
主な機能
- 01ユーザー認証のベースラインを作成
- 02不可能な移動や時間外ログインを検知
- 03不自然なファイル・DBアクセスを特定
- 04特権アカウントの行動を監視
- 05異常を集約してユーザーリスクを算出
活用シーン
- 01侵害された可能性のあるアカウントを調査
- 02退職前の異常なデータアクセスを発見
- 03見慣れない場所からの特権操作を確認
- 04複数地域で使われる共有アカウントを特定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill performing-user-behavior-analyticsインストール後、Claude Code で/performing-user-behavior-analyticsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
ユーザー行動分析の実施
使用するタイミング
次の場合にこのスキルを使用します。
- SOC チームが、異常な認証パターンを通じて侵害されたアカウントを検出する必要がある場合
- インサイダー脅威対策で、ルールベースの検出を超えた行動モニタリングが必要な場合
- 不可能な移動や地理的な異常から、認証情報の侵害が疑われる場合
- 特権アカウントのモニタリングで、ベースラインからの逸脱検出が必要な場合
懲戒処分の唯一の根拠として使用しないでください。UEBA の検出結果は調査が必要な兆候であり、悪意の証明ではありません。
前提条件
- ベースライン作成用に、30 日以上の認証ログおよびアクセスログ履歴がある SIEM
- CIM に正規化された VPN、O365、Active Directory の認証ログ
- 位置情報に基づく異常検出用の GeoIP データベース(MaxMind GeoLite2)
- ID エンリッチメントデータ(部署、役職、上司、通常の勤務時間)
- UBA モジュールまたは同等の UEBA 機能を備えた Splunk Enterprise Security
ワークフロー
ステップ 1:ユーザー認証のベースラインを作成する
履歴データから行動ベースラインを作成します。
index=auth sourcetype IN ("o365:management:activity", "vpn_logs", "WinEventLog:Security")
earliest=-30d latest=-1d
| stats dc(src_ip) AS unique_ips,
dc(src_country) AS unique_countries,
dc(app) AS unique_apps,
count AS total_logins,
earliest(_time) AS first_login,
latest(_time) AS last_login,
values(src_country) AS countries,
avg(eval(strftime(_time, "%H"))) AS avg_login_hour,
stdev(eval(strftime(_time, "%H"))) AS stdev_login_hour
by user
| eval avg_daily_logins = round(total_logins / 30, 1)
| eval login_hour_range = round(avg_login_hour, 0)." +/- ".round(stdev_login_hour, 1)." hrs"
| table user, unique_ips, unique_countries, unique_apps, avg_daily_logins,
login_hour_range, countries
ステップ 2:不可能な移動を検出する
物理的な移動が不可能な時間内に、地理的に離れた場所から行われたログインを特定します。
index=auth sourcetype IN ("o365:management:activity", "vpn_logs")
action=success earliest=-24h
| iplocation src_ip
| sort user, _time
| streamstats current=f last(lat) AS prev_lat, last(lon) AS prev_lon,
last(_time) AS prev_time, last(City) AS prev_city,
last(Country) AS prev_country, last(src_ip) AS prev_ip
by user
| where isnotnull(prev_lat)
| eval distance_km = round(
6371 * acos(
cos(pi()/180 * lat) * cos(pi()/180 * prev_lat) *
cos(pi()/180 * (lon - prev_lon)) +
sin(pi()/180 * lat) * sin(pi()/180 * prev_lat)
), 0)
| eval time_diff_hours = round((_time - prev_time) / 3600, 2)
| eval speed_kmh = if(time_diff_hours > 0, round(distance_km / time_diff_hours, 0), 0)
| where speed_kmh > 900 AND distance_km > 500
| eval alert = "IMPOSSIBLE TRAVEL: ".prev_city.", ".prev_country." -> ".City.", ".Country
| table _time, user, prev_city, prev_country, City, Country, distance_km,
time_diff_hours, speed_kmh, alert
| sort - speed_kmh
ステップ 3:異常なログイン時間を検出する
ユーザーの通常の勤務時間外に行われたログインを特定します。
index=auth action=success earliest=-7d
| eval hour = strftime(_time, "%H")
| eval day_of_week = strftime(_time, "%A")
| eval is_weekend = if(day_of_week IN ("Saturday", "Sunday"), 1, 0)
| eval is_off_hours = if(hour < 6 OR hour > 22, 1, 0)
| join user type=left [
search index=auth action=success earliest=-60d latest=-7d
| eval hour = strftime(_time, "%H")
| stats avg(hour) AS baseline_avg_hour, stdev(hour) AS baseline_stdev_hour,
perc95(hour) AS baseline_latest_hour by user
]
| where (is_off_hours=1 OR is_weekend=1) AND
(hour > baseline_latest_hour + 2 OR hour < baseline_avg_hour - baseline_stdev_hour * 2)
| stats count, values(hour) AS login_hours, values(day_of_week) AS login_days,
values(src_ip) AS source_ips
by user, baseline_avg_hour, baseline_latest_hour
| where count > 0
| sort - count
ステップ 4:通常とは異なるデータアクセスパターンを検出する
ファイルまたはデータベースへの異常なアクセス量を監視します。
index=file_access OR index=sharepoint earliest=-24h
| stats sum(bytes) AS total_bytes, dc(file_path) AS unique_files,
count AS access_count by user
| join user type=left [
search index=file_access OR index=sharepoint earliest=-30d latest=-1d
| stats avg(eval(count)) AS baseline_avg_files,
stdev(eval(count)) AS baseline_stdev_files,
avg(eval(sum(bytes))) AS baseline_avg_bytes
by user
]
| eval bytes_gb = round(total_bytes / 1073741824, 2)
| eval z_score_files = round((unique_files - baseline_avg_files) / baseline_stdev_files, 2)
| where z_score_files > 3 OR bytes_gb > 5
| eval anomaly_level = case(
z_score_files > 5, "CRITICAL",
z_score_files > 3, "HIGH",
bytes_gb > 10, "CRITICAL",
bytes_gb > 5, "HIGH",
1=1, "MEDIUM"
)
| sort - z_score_files
| table user, unique_files, bytes_gb, baseline_avg_files, z_score_files, anomaly_level
ステップ 5:特権の不正使用パターンを検出する
特権アカウントの使用に関する異常を監視します。
index=wineventlog sourcetype="WinEventLog:Security"
(EventCode=4672 OR EventCode=4624 OR EventCode=4648) earliest=-24h
| eval is_privileged = if(EventCode=4672, 1, 0)
| eval is_explicit_cred = if(EventCode=4648, 1, 0)
| stats sum(is_privileged) AS priv_events,
sum(is_explicit_cred) AS explicit_cred_events,
dc(ComputerName) AS unique_hosts,
values(ComputerName) AS hosts_accessed
by TargetUserName, src_ip
| join TargetUserName type=left [
search index=wineventlog EventCode IN (4672, 4624, 4648) earliest=-30d latest=-1d
| stats dc(ComputerName) AS baseline_hosts,
avg(eval(count)) AS baseline_daily_events by TargetUserName
]
| where unique_hosts > baseline_hosts * 2 OR priv_events > baseline_daily_events * 3
| eval risk_score = (unique_hosts / baseline_hosts * 30) + (priv_events / baseline_daily_events * 20)
| sort - risk_score
| table TargetUserName, src_ip, unique_hosts, baseline_hosts, priv_events,
baseline_daily_events, risk_score, hosts_accessed
ステップ 6:リスクスコアを生成し、調査の優先順位を付ける
すべての UEBA シグナルを統合して複合リスクスコアを作成します。
| inputlookup ueba_impossible_travel.csv
| append [| inputlookup ueba_off_hours_access.csv]
| append [| inputlookup ueba_data_access_anomaly.csv]
| append [| inputlookup ueba_privilege_abuse.csv]
| stats sum(risk_points) AS total_risk,
values(anomaly_type) AS anomaly_types,
dc(anomaly_type) AS anomaly_count
by user
| lookup identity_lookup_expanded identity AS user
OUTPUT department, managedBy, priority AS user_priority
| eval final_risk = total_risk * case(
user_priority="critical", 2.0,
user_priority="high", 1.5,
user_priority="medium", 1.0,
1=1, 0.8
)
| sort - final_risk
| head 20
| table user, department, managedBy, anomaly_types, anomaly_count, total_risk, final_risk
主な概念
| 用語 | 定義 |
|---|---|
| UEBA | ユーザーおよびエンティティの行動分析。確立されたベースラインに照らして異常を検出する行動分析です |
| 不可能な移動 | 物理的な移動が不可能な時間内に、地理的に離れた場所から行われたログインイベントです |
| 行動ベースライン | 30~90 日間の履歴データから作成する、通常のユーザー活動パターンの統計プロファイルです |
| Z スコア | 観測値が平均から標準偏差いくつ分離れているかを示す統計指標です。値が 3 を超える場合は異常を示します |
| リスクスコア | 複数の行動異常を、資産の重要度に応じて重み付けして統合した数値スコアです |
| ピアグループ分析 | ユーザーの行動を同じ部署または役職の他のユーザーと比較し、外れ値を特定する分析です |
ツールとシステム
- Splunk UBA:ML 主導の異常検出を実現する、Splunk ES と統合された専用のユーザー行動分析モジュール
- Microsoft Sentinel UEBA:エンティティページと調査グラフを備えた、Azure Sentinel の組み込み UEBA 機能
- Exabeam Advanced Analytics:セッションの連結とタイムラインの自動作成に対応したスタンドアロン UEBA プラットフォーム
- Securonix:インサイダー脅威検出用の事前構築済み行動モデルを備えたクラウドネイティブの SIEM/UEBA
よくあるシナリオ
- 侵害されたアカウント:不可能な移動+時間外ログイン+通常とは異なるアプリへのアクセス=認証情報が侵害された可能性が高い
- インサイダーによるデータ窃取:退職前の予告期間中に、従業員が通常の 10 倍のファイル量にアクセスする
- 権限昇格の悪用:管理者アカウントが通常とは異なる場所から使用され、通常の範囲外のシステムにアクセスする
- 共有アカウントの検出:サービスアカウントが複数の地理的な場所から同時にログインする
- 休眠アカウントの再有効化:90 日以上活動のなかったアカウントが、突然、特権操作を実行する
出力形式
UEBA ANOMALY REPORT — Weekly Summary
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Period: 2024-03-11 to 2024-03-17
Users Baselined: 2,847
Anomalies Detected: 23
TOP RISK USERS:
# User Dept Risk Anomalies
1. jsmith Finance 94.5 Impossible travel (NYC->Moscow, 2h), off-hours access, 15GB download
2. admin_svc01 IT Ops 82.0 Login from 12 new IPs, 47 hosts accessed (baseline: 8)
3. mwilson HR 67.3 Off-hours file access (2AM), 3x normal download volume
INVESTIGATION STATUS:
jsmith: Escalated to Tier 2 — possible account compromise (IR-2024-0445)
admin_svc01: Under review — may be new automation deployment (checking with IT Ops)
mwilson: Pending HR context — employee on notice period, monitoring increased
コメント
Markdown 対応