docs

Sensor の仕組み

URSUS が Linux システムからイベントを収集する技術的アプローチの詳細


process Process Collector

netlink (cn_proc) でプロセス起動をカーネルから push 通知で受け取る

目的

URSUS が観測する 4 つのイベントタイプの中で最も重要なのが プロセス起動です。攻撃者の行動はほぼ必ず「何かのプロセスを起動する」という 形で表面化します。シェル、payload バイナリ、永続化のための cron タスク、 横展開の psexec — 全てプロセス起動として観測できます。

採用方式: cn_proc netlink

プロセス起動を観測する Linux 上の選択肢は複数あります。URSUS は kernel から直接 push 通知を受ける方式を採用しています。

方式取りこぼし必要権限備考
cn_proc netlink (採用) なし CAP_NET_ADMIN カーネルが exec(2) のたびに通知。リアルタイム
psutil ポーリング あり (poll 間隔より短命) 不要 DESIGN.md の初版方針。実装簡単だが取りこぼし大
auditd なし root execve syscall を audit ルールで購読。出力フォーマットが煩雑
eBPF (kprobe) なし CAP_BPF 商用 EDR の主流実装。bcc / libbpf-CO-RE への依存が必要

cn_proc とは

cn_proc (process events connector) は、Linux カーネルが connector インタフェースを介して送出するマルチキャストイベントです。netlink ソケットの NETLINK_CONNECTOR プロトコルファミリーで購読します。

カーネルは以下のイベントを通知します:

  • PROC_EVENT_FORK: fork(2) 完了時
  • PROC_EVENT_EXEC: execve(2) 成功時
  • PROC_EVENT_EXIT: プロセス終了時
  • PROC_EVENT_UID, PROC_EVENT_GID: 権限変更時
  • その他 (sid, ptrace 等)

URSUS は EXEC のみを購読しています。検知に必要な情報 (プロセス名・コマンドライン・実行ファイル・親プロセス)は exec の タイミングで揃うためです。

  bytes 0  ─┐
            │  ┌──────────────────────────────┐
   nlmsghdr │  │ len, type, flags, seq, pid   │  16 bytes
            │  └──────────────────────────────┘
  bytes 16 ─┤
            │  ┌──────────────────────────────┐
   cn_msg   │  │ idx, val, seq, ack, len, fl  │  20 bytes
            │  └──────────────────────────────┘
  bytes 36 ─┤
            │  ┌──────────────────────────────┐
   evt_hdr  │  │ what, cpu, timestamp_ns      │  16 bytes
            │  └──────────────────────────────┘
  bytes 52 ─┤
            │  ┌──────────────────────────────┐
  body (exec)│ │ pid, tgid                    │  8 bytes
            │  └──────────────────────────────┘
  bytes 60 ─┘
              

PROC_EVENT_EXEC を含む netlink メッセージのレイアウト

出力されるイベント

非正規化カラム

カラム値の例用途
pid4567同 PID で前後コンテキストを引く
ppid1000プロセスツリー再構築
userwww-data権限昇格検知
process_namebashR001 (web→shell) 等で照合
parent_process_namenginx親プロセス基準のルール
cmdlinebash -c curl ... | shregex 検知
exe_path/usr/bin/bash/tmp 配下からの実行検知 (R010)

制限と既知の挙動

  • fork のみのイベントは取れない: EXEC を購読しているため。
  • extreme short-lived プロセス: netlink 通知後、/proc 情報を読み取る前に終了したプロセスは詳細が取れない。
  • 権限: CAP_NET_ADMIN が必要。

file File Collector

inotify (watchdog) によるファイル変更のリアルタイム検知

目的

攻撃者の永続化やデータ改竄は、最終的に「ファイル書き込み」として表面化します。 /etc/passwd の書き込み、SSH 鍵の改変、cron タスクの投入などを監視します。

採用方式: inotify (watchdog 経由)

方式PID/Process 取得必要権限備考
inotify (採用) 不要 カーネルの fs 通知。watchdog ライブラリで Python から扱う
fanotify ◎ (PID/exe path) CAP_SYS_ADMIN 5.1+ で FAN_REPORT_FID
auditd file watch root auditctl -w /etc/passwd -p wa
inotify は "誰が変更したか" を返さない

URSUS の現在の実装では、ファイルが改変されたことは分かりますが 「どのプロセスが書き込んだか」は分かりません。

除外パターンと自己フィードバック防止

URSUS 自体の DB 更新による無限ループを防ぐため、DB ディレクトリは無条件で除外されます。 また、glob パターンによる除外設定も可能です。

出力されるイベント

非正規化カラム

カラム
file_path/etc/passwd
file_opcreate / modify / delete / move

network Network Collector

psutil による TCP 接続テーブル差分ポーリング

目的

新規 LISTEN(リバースシェル待ち受け)や新規 ESTABLISHED(C2 通信、データ送信)を観測します。

採用方式: psutil 差分ポーリング

network センサはポーリング方式です。2 秒間隔(既定)で /proc/net/tcp を読み取り、前回のスナップショットとの差分を抽出します。

取りこぼしを許容している

ポーリング間隔より短命な接続(1秒以内に閉じる curl など)は見えないことがあります。

出力されるイベント

非正規化カラム

カラム例 (ESTABLISHED)例 (LISTEN)
pid4567999
process_namepython3sshd
local_port5432122
remote_addr192.0.2.10NULL
conn_stateESTABLISHEDLISTEN

auth Auth Collector

systemd-journald を journalctl 経由で購読し SSH/sudo を観測

目的

SSH ブルートフォース、初期アクセス確立、sudo による権限昇格を観測します。

採用方式: journalctl 購読

journalctl -f --output=json を子プロセスとして起動し、新規ログをリアルタイムに受け取ります。

   journalctl -f --output=json     ─────  カーネル
   ────────────────────────────              │
        │                                    │ inotify / signalfd
        ▼
   stdout (1行 1JSON)
        │
        ▼
   Python: select.poll()  ─────── stop_event チェック
        │
        ▼
   _handle_line(line): JSON 解析 → 正規表現で分類
              

出力されるイベント

非正規化カラム

カラム値の例
auth_userroot
auth_resultsuccess / failure / sudo
source_ip203.0.113.5
process_namesshd
cmdline(sudo の場合) /usr/bin/cat /etc/shadow