アップデート一覧に戻る
New releaseAug 1, 2026

maltrail v2.2

公開ブラックリスト、静的マルウェアトレイル、ヒューリスティック分析を活用し、DNS、HTTP、IPトラフィックにおける脅威を識別するリアルタイム悪意トラフィック検出システム。

共有

Maltrail

License Sensor Server Trails X

悪性トラフィック検出システム。 Maltrail は、悪性と知られているものとの接触をネットワーク上で監視し、何が観測されたのか、なぜ悪性と判断されたのかを、一行で伝えます。

"2026-08-07 09:14:22.117034" gw 10.13.13.2 57809 1.1.1.1 53 UDP DNS malware.bakewithdavid.com "asyncrat (malware)" (static)

ルール言語も、チューニングの儀式も、ML (機械学習) も不要です。trail とは、悪性のものに属することが知られているドメイン、URL、IP アドレス、IP:port、または User-Agent のことであり、Maltrail はそれらがネットワーク上 (回線上) に現れたときに通知します。


なぜ Maltrail なのか

ほとんどのネットワーク検出ツールは、挙動 (behaviour) の記述を求めます。Maltrail は、実際のインシデントのほとんどに答える、より単純な問いを投げかけます: このホストは、すでに悪性と判明している相手と通信しているか?

  • 150 万以上の trail を、3,000 を超える精選された静的リストと 46 の公開フィードから収集し、毎日更新・増加させています。マルウェア — C2 ドメイン、ドロッパー、スティーラー、APT インフラ — に大きく重み付けされています。なぜなら、実際の侵害で現れるのはそうしたものだからです。
  • Trail はプレーンテキストです。 1 行に 1 つのインジケータを、読み取り、grep、プルリクエストが可能なファイルに格納します。だからこそカバレッジは最新の状態を保ち、「なぜこれが発火したのか?」にいつでも答えられるのです。
  • 考えなくて済むほど高速です。 現実的なトラフィック構成であれば、シングルコアで 10 GbE リンクを処理できます。パフォーマンス を参照してください。
  • ヒューリスティクスは代替ではなく、その上に追加されます — それぞれがイベント内で名前付きで示され、素のスコアで示されることはありません: ポートスキャン、UDP スキャン、Web スキャン、DNS 枯渇、DGA 形状のルックアップ (エントロピーと子音の閾値、過剰な NXDOMAIN)、シンクホール・差し押さえ・パークされたドメイン、長いドメイン、直接 IP および IoT マルウェアのダウンロード、不審なユーザーエージェントとプロキシプローブ。

アーキテクチャ

2 つの独立したプロセスです。1 台のマシンでも複数台でも実行できます。

   ┌──────────┐   events (UDP or file)   ┌──────────┐
   │  sensor  │ ───────────────────────► │  server  │ ◄── browser
   └──────────┘                          └──────────┘
    Rust                                  Python
    libpcap + PACKET_FANOUT               reporting UI + API
    trail matching, heuristics

センサーはローカルにログを記録 (LOG_DIR)、リモートサーバーへ送信 (LOG_SERVER)、またはその両方を行うことができます。既存の SIEM 向けには、syslog 経由の CEF (SYSLOG_SERVER) と Logstash JSON (LOGSTASH_SERVER) も出力します。


パフォーマンス

センサーは Rust で実装され、キャプチャワーカーごとに 1 スレッド、単一の不変 trail ストアを共有します。トラフィック種別ごとのパケットあたりコスト:

トラフィックパケットあたり
ICMP echo (58 B)101 ns
TCP SYN (70 B)302 ns
bulk TLS (1,473 B)402 ns
DNS query, warm cache (93 B)452 ns
mixed traffic (866 B average)552 ns
HTTP request (169 B)602 ns
DNS query, every name unique (DGA flood)1,102 ns

ワーカーは可変状態を一切共有しないため、そのコストが、コアを追加するごとに得られる性能そのものです。866 バイトの混在トラフィックを再生した結果:

ワーカー数packets/sGbit/s1 ワーカー比
11,687,99111.691.00×
23,209,62722.241.90×
45,379,43637.273.19×
88,552,23159.255.07×
1610,165,77370.436.02×

1 コアで 10 GbE を飽和させます。 スケーリングは 4 ワーカーまでほぼ線形で、その後は 8 物理コアのマシン上で頭打ちになります。残りは SMT であるためです — ロック競合ではなくハードウェアの限界です。

旧 Python センサーとの比較です。同じ 300,000 パケットのキャプチャ同じ 1,505,265 trailと同一構成で、各 1 ワーカーずつ再生しました — 起動は除外しているため、これは定常状態のパケットコストです。ここでの数値はどちらもプロセス全体のもの (pcap 読み取りとディスパッチを含む) であり、そのためセンサーの数値は、上記で単独測定した 552 ns のパケット経路よりも高くなっています:

パケットあたりpackets/s
センサー (Rust)865 ns1,156,423
旧センサー (Python)23,448 ns42,648
27倍高速

自分で再現できます — ハーネスはコミットされており、両センサーのイベント数を出力するため、スループットの数値を、その正確性の文脈なしに引用することはできません:

python3 sensor/tools/bench_compare.py --packets 300000 --trails ~/.maltrail/trails.csv --repeat 3

メモリ使用量はコア数に応じて増えません。150 万 trail のストアは 68.5 MB で、1.2 秒で構築され、すべてのワーカーが不変に共有します。

デフォルトはキャプチャワーカー 1 つで、約 110 万 packets/s を処理し、ほぼすべてのセンサーホストに十分です。追加ワーカーは明示的なオプトイン (CAPTURE_FANOUT) です。カーネルはキャプチャをフローハッシュする一方、スキャンヒューリスティクスは送信元ごとにカウントするためです。1 ワーカーが発するヒューリスティックアラートのうち、2 ソケットでは 91%、4 では 86%、8 では 65% が維持されます。厳密な trail 検出は、ワーカー数によらず同一です。maltrail_capture_dropped_total が指示したときにスケールアウトしてください。それまでは不要です。

AMD Ryzen 7 PRO 4750U (8 物理コア)、ヒューリスティクス有効、実トライルセット、3 回の実行の最速値。実行やハードウェアによって比率は 14〜27 倍の範囲で変動します。上記のパケットあたりコストが、ワーカーが吸収できるトラフィック量を左右します。これらはソフトウェア経路の数値です — 実環境の NIC ではドライバとリングのコストが加わるため、ご自身のハードウェアで測定し、maltrail_capture_dropped_total を監視してください。方法、プロトコル別の内訳、命令数、プロファイラ出力は sensor/docs/REPORT.md にあります。


クイックスタート

Linux、libpcap、センサー用に Rust 1.74+、サーバー用に Python 3.7+ が必要です。

x86_64aarch64 向けのビルド済みセンサーバイナリが、SHA-256 チェックサム付きで各 リリース に添付されています。そのため Rust ツールチェーンはソースからのビルドにのみ必要です。それでもビルドする場合:

git clone --depth 1 https://github.com/stamparm/maltrail.git
cd maltrail

# 1. build the sensor
cd sensor && cargo build --release && cd ..

# 2. let it capture without running as root
sudo setcap cap_net_raw,cap_net_admin=eip sensor/target/release/maltrail-sensor

# 3. give it somewhere to write events (LOG_DIR, /var/log/maltrail by default)
sudo install -d -o "$USER" -g "$USER" -m 750 /var/log/maltrail

# 4. check the deployment before trusting it — exits non-zero if anything is wrong
sensor/target/release/maltrail-sensor -T

# 5. run it (first start builds the trail set; takes a minute)
sensor/target/release/maltrail-sensor

別のターミナル、または別のマシンで:

python3 server.py

次に http://127.0.0.1:8338 を開き、maltrail.conf (USERS) の認証情報でログインします。

-T は「これで動くのか?」を確認するためのショートカットです。構成、trail、ホワイトリスト、ログディレクトリ、キャプチャフィルタ、権限を検証し、何が不足しているかを正確に教えてくれます:

[o] log directory: '/var/log/maltrail' is writable
[o] capture privileges: CAP_NET_RAW present
[o] capture filter: udp or icmp or (tcp and (tcp[tcpflags] == tcp-syn or port 80 or port...
[o] interface: any
[o] workers: 16 (PACKET_FANOUT required; verify with tools/fanout_check.py as root)
[o] whitelist: 3440 entries, 18 CIDR range(s)
[o] trails: 1505265 loaded (0 malformed row(s)), ipv4=144758 ipv4:port=253517 ipv6=2014 wildcard=29
[o] heuristics: on (disabled: none)
[i] configuration test PASSED

手順 2 または 3 を省略することは、起動しても何も検知しないセンサーになってしまう最も一般的な原因です。-T はその両方を指摘します。

サービスとして実行

sudo useradd --system --no-create-home --shell /usr/sbin/nologin maltrail
sudo rsync -a --exclude .git . /opt/maltrail/
sudo cp /opt/maltrail/maltrail-{server,sensor}.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now maltrail-server maltrail-sensor

これでインストールは完了です — 作成するディレクトリも、setcap もありません。ユニットは systemd の LogsDirectory=/StateDirectory= により /var/log/maltrail (イベント) と /var/lib/maltrail (trail セット) を作成・所有し、両プロセスを権限のない maltrail ユーザーとして読み取り専用ファイルシステム上で実行し、センサーには CAP_NET_RAWCAP_NET_ADMIN だけを正確に付与します — それ以外は何もなく、どこにも root はありません。センサーは ExecStartPre として -T を実行するため、壊れたデプロイは何も分からないまま実行される代わりに、systemctl start の時点で失敗します。

確認方法: systemctl status maltrail-sensorjournalctl -u maltrail-sensor -f を実行します。

Docker

docker compose -f docker/docker-compose.yml up -d

docker/README.md を参照してください。


構成

すべては maltrail.conf に集約され、[Sensor][Server] に分かれています。特に知っておく価値のあるオプション:

オプション機能
MONITOR_INTERFACEキャプチャするインターフェース、または any
CAPTURE_FILTERBPF フィルタ。デフォルトでは、バルクの回線レートトラフィックをユーザースペースに持ち込まない
PROCESS_COUNTキャプチャワーカー数。コアごとに 1 つが妥当なデフォルト
LOG_DIRイベントの書き込み先 (/var/log/maltrail)
TRAILS_FILE構築された trail セットの場所 (~/.maltrail/trails.csv。ユニット実行時は /var/lib/maltrail)
LOG_SERVERローカル記録の代わりに、またはローカル記録に加えて、イベントをリモートサーバーへ送信する
STATS_ADDRESSPrometheus メトリクスを公開する (センサー。設定時のみ有効)
UPDATE_PERIODtrail の更新頻度
USER_WHITELIST独自の「絶対にアラートしない」リスト
CUSTOM_TRAILS_DIR同梱の trail に加える独自の trail

Trails

trails/static/malware/asyncrat.txt      # one indicator per line
trails/static/malicious/…
trails/static/suspicious/…
trails/feeds/*.py                       # public feeds, pulled on update

インジケータの追加は、テキストファイルに行を 1 行足すだけです。フィードの追加は、小さな Python モジュールを 1 つ加えるだけです。どちらも通常のプルリクエストであり、この敷居の低さこそが、セットが有用であり続ける理由です。

独自のインジケータは CUSTOM_TRAILS_DIR に置きます。通知されたくないものはすべて USER_WHITELIST に置きます。


イベント

検知ごとに 1 行、空白区切り、必要に応じて CSV クォート:

"<time>" <sensor> <src_ip> <src_port> <dst_ip> <dst_port> <proto> <type> <trail> "<info>" <reference>

type は何が一致したか — DNSIPIPORTURLPATHHTTPUAPORT — を示し、info はなぜ悪性と判断されたか、reference は trail の出典 ((static)、フィード名、または (heuristic)) を示します。


運用

  • -T は構成を検証して終了します。デプロイのゲートとして使用でき、systemd ユニットは ExecStartPre として実行します。

  • STATS_ADDRESS は Prometheus メトリクスを公開します。アラートを設定する価値のある 4 つで、いずれも このセンサーはあなたが思っているものを検知していない ことを意味します:

    メトリクス意味
    maltrail_up == 0キャプチャワーカーが 1 つも稼働していない — このホストは監視されていません
    rate(maltrail_capture_dropped_total)リングがパケットをドロップしている — 検知の取りこぼし
    rate(maltrail_local_log_errors_total)検知は生成されたが失われた
    maltrail_trail_generation not advancingtrail の更新が停止している

    他にも有用なもの: maltrail_log_dir_free_bytes (後述) と maltrail_state_saturations_total。後者は状態枯渇フラッドがヒューリスティクスを縮小したときに非ゼロになります。厳密な trail マッチングは、設計上その影響を受けません。

  • systemctl reload (SIGHUP) は再起動なしで trail を再読み込みします。他の手段で更新された trail も、アトミックスワップにより 1 秒以内に反映されます — 再起動もパケットドロップもありません。

  • 凝縮オブザーバブルストア (USE_CONDENSED_STORAGEmeta.sqlite) は、サーバーの /meta 新規性ビューとレトロハントビューにデータを供給するもので、旧センサーが生成するのと同じ形式で書き込まれ、両者はパリティハーネスによって行ごとに比較されます。センサー間の意図的な違いはすべて sensor/docs/COMPATIBILITY.md に列挙されています。

イベント保持

Maltrail はイベントの証跡を決して削除しません。 ログを失効させる保持設定はなく、それは意図的なものです。これらはインシデント後に振り返るための記録であり、静かに破棄してしまうツールは、それらが最も必要になる一週間において、役に立たないどころか有害です。

そのため、空き容量は無視するものではなく、運用するものになります:

  • 耐久性のあるコピーをサーバー外へ送ります。 LOG_SERVER (または SYSLOG_SERVER / LOGSTASH_SERVER) により、サーバーまたは SIEM が記録の正規システムとなり、センサーのローカルファイルはバッファになります。これが保持戦略です。ローカルディスクは保持戦略ではありません。
  • maltrail_log_dir_free_bytes に十分な余裕をもってアラートを設定します。 -T もこれを報告し、10 GB 未満になると警告します。ゼロに達するとセンサーは追記できなくなり、検知が失われます。
  • アーカイブはご自身の判断で行います。 容量が必要であれば、ご自身のスケジュールで古い日次ログを圧縮または移動してください。レポート UI は履歴ログをシーク可能なプレーンファイルとして提供するため、その場で圧縮すると、それらの日がインターフェースから消えます — 別の場所にアーカイブしてください。

ポリシーで削除が要求される場合 (イベントログには IP アドレスとドメインが含まれ、一部の法域では個人データに該当します)、それは運用者の明示的な判断です — センサーのデフォルトが静かに実行するのではなく、ご自身のツールで意図的に行ってください。


ドキュメント

sensor/docs/INSTALL.mdインストール、権限、構成、トラブルシューティング
sensor/docs/ARCHITECTURE.mdセンサーの内部動作
sensor/docs/COMPATIBILITY.md旧センサーとの意図的な違いのすべて
sensor/docs/REPORT.md測定値、プロファイル、テスト結果
sensor/docs/ROADMAP.md未解決の項目
old/README.md旧 Python センサー。参照用およびテストオラクルとして維持

コントリビューション

最も価値のあるコントリビューションは trail です。出典付きで、適切なファイルに 1 行追加するだけです。フィード、バグ報告、センサーの開発も同様に歓迎します。

センサーの完全なゲートは 1 つのコマンドです:

bash sensor/tools/check.sh

これはフォーマット、リント、debug と release の両方のプロファイルでのテストスイートを実行し、コーパスを現在のセンサーと旧 Python センサーの両方で再生して、バイト単位で同一のイベントを要求します。Python 側は bash tests/run.sh になります。


ライセンス

MIT。LICENSE を参照してください。

カテゴリ