Splunk とは

Splunk は機械生成データ(ログ・メトリクス・イベント)を収集・インデックス化・検索・可視化するためのプラットフォームです。SOC(セキュリティオペレーションセンター)では SIEM(Security Information and Event Management)として広く採用されています。

エディションの概要:

  • Splunk Free: 1日500MBまでのインジェスト制限あり。個人学習・小規模環境向け
  • Splunk Enterprise: 商用版。フル機能
  • Splunk Cloud: SaaS版

このレッスンでは Splunk Free(またはEnterprise 60日トライアル) を使用します。

SOCにおけるSplunkの主な役割:

用途説明
ログ集中管理サーバー・ネットワーク機器・セキュリティ機器のログを一元収集
リアルタイム検索SPL(Search Processing Language)で高速検索・集計
アラート条件にマッチするイベントを検出して通知
ダッシュボード可視化パネルを組み合わせた運用状況のモニタリング画面
実習データについて

このレッスンで使用するログは演習用に作成したサンプルデータです。実際の本番サーバーのログを無断で収集・解析することは、プライバシーポリシー違反や不正アクセスに該当する場合があります。必ず自分が管理するシステムのログ、または演習用のサンプルデータのみを使用してください。

演習環境のセットアップ

Splunk のインストール

Splunk公式サイト(https://www.splunk.com/en_us/download.html)から

Splunk Enterprise(60日トライアル)の .debパッケージをダウンロード

インストール

sudo dpkg -i splunk-9.x.x-linux-amd64.deb

Splunk を起動(初回は利用規約への同意が必要)

sudo /opt/splunk/bin/splunk start —accept-license

管理者ユーザーのパスワードを設定するプロンプトが表示される

Please enter an administrator username: admin

Please enter a new password: (任意のパスワードを入力)

起動確認

sudo /opt/splunk/bin/splunk status

splunkd is running (PID: XXXXX).

ブラウザで http://localhost:8000 にアクセス

admin / 設定したパスワード でログイン

演習用サンプルログの準備

作業ディレクトリを作成

mkdir -p ~/splunk-lab/logs

Apache アクセスログのサンプルを作成

cat > ~/splunk-lab/logs/apache_access.log << ‘EOF’ 192.168.1.100 - - [19/Mar/2026:09:00:01 +0900] “GET /index.html HTTP/1.1” 200 4523 ”-” “Mozilla/5.0” 192.168.1.101 - - [19/Mar/2026:09:00:15 +0900] “GET /about.html HTTP/1.1” 200 2341 ”-” “Mozilla/5.0” 10.0.0.5 - - [19/Mar/2026:09:01:00 +0900] “GET /admin/ HTTP/1.1” 403 512 ”-” “sqlmap/1.7” 10.0.0.5 - - [19/Mar/2026:09:01:01 +0900] “GET /admin/login.php HTTP/1.1” 200 1234 ”-” “sqlmap/1.7” 10.0.0.5 - - [19/Mar/2026:09:01:02 +0900] “GET /admin/login.php?id=1’ HTTP/1.1” 500 567 ”-” “sqlmap/1.7” 10.0.0.5 - - [19/Mar/2026:09:01:03 +0900] “GET /admin/login.php?id=1’+OR+‘1’=‘1 HTTP/1.1” 200 9999 ”-” “sqlmap/1.7” 10.0.0.5 - - [19/Mar/2026:09:01:04 +0900] “GET /admin/login.php?id=1+UNION+SELECT+1,2,3— HTTP/1.1” 200 9999 ”-” “sqlmap/1.7” 192.168.1.102 - - [19/Mar/2026:09:05:00 +0900] “GET /products.html HTTP/1.1” 200 3456 ”-” “Mozilla/5.0” 10.0.0.6 - - [19/Mar/2026:09:10:00 +0900] “GET /.env HTTP/1.1” 404 215 ”-” “python-requests/2.28” 10.0.0.6 - - [19/Mar/2026:09:10:01 +0900] “GET /.git/config HTTP/1.1” 404 215 ”-” “python-requests/2.28” 10.0.0.6 - - [19/Mar/2026:09:10:02 +0900] “GET /wp-admin/ HTTP/1.1” 404 215 ”-” “python-requests/2.28” 10.0.0.6 - - [19/Mar/2026:09:10:03 +0900] “GET /phpmyadmin/ HTTP/1.1” 404 215 ”-” “python-requests/2.28” 10.0.0.6 - - [19/Mar/2026:09:10:04 +0900] “GET /backup.zip HTTP/1.1” 404 215 ”-” “python-requests/2.28” 192.168.1.100 - - [19/Mar/2026:09:15:00 +0900] “POST /contact.php HTTP/1.1” 200 789 ”-” “Mozilla/5.0” 10.0.0.7 - - [19/Mar/2026:09:20:00 +0900] “GET /<script>alert(1)</script> HTTP/1.1” 400 312 ”-” “Mozilla/5.0” EOF

SSH 認証ログのサンプルを作成

cat > ~/splunk-lab/logs/auth.log << ‘EOF’ Mar 19 09:00:01 webserver sshd[1234]: Accepted publickey for admin from 192.168.1.50 port 52341 ssh2 Mar 19 09:30:00 webserver sshd[1235]: Failed password for root from 185.220.101.5 port 41234 ssh2 Mar 19 09:30:01 webserver sshd[1235]: Failed password for root from 185.220.101.5 port 41235 ssh2 Mar 19 09:30:02 webserver sshd[1235]: Failed password for admin from 185.220.101.5 port 41236 ssh2 Mar 19 09:30:03 webserver sshd[1235]: Failed password for ubuntu from 185.220.101.5 port 41237 ssh2 Mar 19 09:30:04 webserver sshd[1235]: Failed password for pi from 185.220.101.5 port 41238 ssh2 Mar 19 09:30:05 webserver sshd[1235]: Failed password for test from 185.220.101.5 port 41239 ssh2 Mar 19 09:30:06 webserver sshd[1235]: Failed password for oracle from 185.220.101.5 port 41240 ssh2 Mar 19 09:30:07 webserver sshd[1235]: Failed password for ftpuser from 185.220.101.5 port 41241 ssh2 Mar 19 09:30:08 webserver sshd[1235]: Failed password for postgres from 185.220.101.5 port 41242 ssh2 Mar 19 09:30:09 webserver sshd[1235]: Failed password for user from 185.220.101.5 port 41243 ssh2 Mar 19 09:30:10 webserver sshd[1235]: message repeated 50 times: [ Failed password for invalid user from 185.220.101.5] Mar 19 09:31:00 webserver sshd[1236]: Accepted password for deploy from 10.0.0.100 port 34512 ssh2 Mar 19 10:00:00 webserver sshd[1237]: Failed password for root from 45.142.212.100 port 55123 ssh2 Mar 19 10:00:01 webserver sshd[1237]: Failed password for root from 45.142.212.100 port 55124 ssh2 Mar 19 10:15:00 webserver sudo[1238]: admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/bin/bash Mar 19 10:15:01 webserver sudo[1238]: pam_unix(sudo:session): session opened for user root by admin(uid=0) EOF

Splunk へのデータ取り込み

Splunk CLI でファイルをインデックスに投入

sudo /opt/splunk/bin/splunk add oneshot ~/splunk-lab/logs/apache_access.log
-sourcetype access_combined
-index main

sudo /opt/splunk/bin/splunk add oneshot ~/splunk-lab/logs/auth.log
-sourcetype linux_secure
-index main

または Splunk Web UI から:

Settings → Add Data → Upload → ファイルを選択

Source type: access_combined(Apache用)または linux_secure(SSH用)

Index: main

SPL(Search Processing Language)の基本

SplunkはSQLに似たSPLを使って検索・集計します。

— すべてのイベントを検索(最新100件) index=main

— 特定のソースタイプのみ検索 index=main sourcetype=access_combined

— キーワード検索(スペース区切りでAND条件) index=main sourcetype=linux_secure “Failed password”

— 特定のIPアドレスのイベントを絞り込む index=main sourcetype=access_combined clientip=“10.0.0.5”

— 時間範囲を指定(検索バーの時間セレクターか earliest/latest で指定) index=main earliest=-1h latest=now

— フィールドの値で絞り込む index=main sourcetype=access_combined status=500

実習 1 — SQLインジェクション攻撃の検出

— SQLインジェクションの典型的なパターンを検索 index=main sourcetype=access_combined | search uri=“UNION” OR uri=“SELECT” OR uri=”” OR uri=“OR+1=1

— より精緻に: 5xxエラーやsqlmapのUser-Agentを検索 index=main sourcetype=access_combined | search useragent=“sqlmap” OR status=500

— 攻撃元IPのリクエスト数を集計(上位10件) index=main sourcetype=access_combined | stats count by clientip | sort -count | head 10

— 結果例: — clientip count — 10.0.0.5 5 — 10.0.0.6 5 — 10.0.0.7 1 — 192.168.1.100 2 — 192.168.1.101 1

— SQLi疑いのあるURIを時系列で表示 index=main sourcetype=access_combined (uri=“UNION” OR uri=“SELECT” OR useragent=“sqlmap”) | table _time, clientip, uri, status, useragent | sort _time

SPLのパイプ(|)について

SPLはLinuxのパイプに似た概念を使います。検索結果を次のコマンドに渡して集計・変換・可視化を連鎖させます。stats(集計)、table(表形式表示)、chart(グラフ用集計)、sort(並び替え)、head(上位N件)などがよく使われます。

実習 2 — ディレクトリスキャン・偵察の検出

— 404エラーが多い送信元IPを検出(スキャンの特徴) index=main sourcetype=access_combined status=404 | stats count by clientip | where count > 3 | sort -count

— 結果例: — clientip count — 10.0.0.6 5

— スキャン対象となったURLを確認 index=main sourcetype=access_combined clientip=“10.0.0.6” | table _time, uri, status, useragent

— 結果例: — _time uri status useragent — 2026-03-19 09:10:00 /.env 404 python-requests/2.28 — 2026-03-19 09:10:01 /.git/config 404 python-requests/2.28 — 2026-03-19 09:10:02 /wp-admin/ 404 python-requests/2.28 — 2026-03-19 09:10:03 /phpmyadmin/ 404 python-requests/2.28 — 2026-03-19 09:10:04 /backup.zip 404 python-requests/2.28

— 短時間に多数リクエストを送るIP(1分あたり10件以上) index=main sourcetype=access_combined | bucket _time span=1m | stats count by _time, clientip | where count >= 5 | sort -count

実習 3 — SSH ブルートフォース攻撃の検出

— “Failed password” のエントリを検索 index=main sourcetype=linux_secure “Failed password” | stats count by host, src | sort -count

— 結果例: — host src count — webserver 185.220.101.5 60 — webserver 45.142.212.100 2

— 攻撃元IPのブルートフォース詳細:試行されたユーザー名の一覧 index=main sourcetype=linux_secure “Failed password” src=“185.220.101.5” | rex “Failed password for (?:invalid user )?(?P<attempted_user>\S+) from” | stats count by attempted_user | sort -count

— 結果例: — attempted_user count — root 2 — admin 1 — ubuntu 1 — pi 1 — test 1 — …

— 成功したSSHログインを確認(攻撃の成否を確認) index=main sourcetype=linux_secure “Accepted” | table _time, host, src, user

— 結果例: — _time host src user — 2026-03-19 09:00:01 webserver 192.168.1.50 admin — 2026-03-19 09:31:00 webserver 10.0.0.100 deploy

Tor出口ノードと攻撃者IPの相関

実習で使用した 185.220.101.545.142.212.100 は、実際にTorの出口ノードやVPSとして攻撃に使われているIPアドレスの例です。Splunkでは脅威インテリジェンスフィードのIPリストと照合するルックアップテーブル機能があり、自動的に既知の悪意あるIPを検出できます。

実習 4 — タイムライン可視化とダッシュボード構築

— 1分ごとのHTTPリクエスト数の時系列グラフ index=main sourcetype=access_combined | timechart span=1m count by clientip

— ステータスコード別の時系列グラフ index=main sourcetype=access_combined | timechart span=1m count by status

— SSH失敗ログインの時系列 index=main sourcetype=linux_secure “Failed password” | timechart span=1m count by src

— ダッシュボードへのパネル追加手順: — 1. 上記クエリを検索バーで実行 — 2. 「Visualization」タブでグラフを確認 — 3. 「Save As」→「Dashboard Panel」をクリック — 4. ダッシュボード名を入力して保存 — 5. Dashboards メニューから確認

— 地理的分散(送信元国別) index=main sourcetype=access_combined | iplocation clientip | stats count by Country | sort -count

実習 5 — アラートの設定

Splunkでは検索条件に一致するイベントを定期的に監視し、アラートを発報できます。

— アラート対象のクエリを作成 — 例:5分以内にSSH失敗ログインが10件を超えたIPを検出

index=main sourcetype=linux_secure “Failed password” | stats count by src | where count > 10

— Splunk Web UI での操作: — 1. 上記クエリを検索バーに入力して実行 — 2. 「Save As」→「Alert」をクリック — 3. 以下を設定: — Title: SSH Brute Force Detection — Alert type: Scheduled(スケジュール実行) — Time Range: Last 5 minutes — Schedule: Every 5 minutes — Trigger condition: Number of Results > 0 — 4. Trigger Actions で通知方法を設定: — - Send email(メール通知) — - Log event(Splunkイベントに記録) — - Add to Triggered Alerts(アラートリストに追加) — 5. 「Save」で設定完了

— アラートの確認 — Activity → Triggered Alerts でアラート一覧を確認

相関検索(Correlation Search)の考え方

高度なSOC運用では単一ルールのアラートではなく、複数の弱いシグナルを組み合わせた相関検索が重要です。例えば「同じIPが①偵察スキャンを行い②SSHブルートフォースを試み③短時間後にSSH成功ログインがある」という複合条件は、個々のアラートより精度が高く、侵害の可能性を示します。

実習のまとめ:検出した攻撃の整理

— 全攻撃元IPの総合サマリ index=main | stats count(eval(sourcetype=“access_combined” AND status=404)) as scan_requests, count(eval(sourcetype=“linux_secure” AND match(_raw, “Failed password”))) as ssh_fails, count(eval(sourcetype=“access_combined” AND match(uri, “UNION|SELECT”))) as sqli_attempts by clientip, src | eval suspicious_score = scan_requests + ssh_fails + (sqli_attempts * 3) | sort -suspicious_score | head 10


やってみよう — 演習ミッション

演習ミッション

以下の課題を自分の手で実施してみましょう。

ミッション 1(基礎): サンプルのApacheログからステータスコード 200 のリクエストのみを抽出し、最もアクセスが多いURIをトップ5で表示してください。(ヒント:stats count by uri | sort -count | head 5

ミッション 2(中級): SSH ログから「成功したログイン(Accepted)」と「失敗したログイン(Failed password)」の両方があるIPアドレスを見つけてください。(ヒント:2つのサブサーチをevalまたはjoinで組み合わせる)

ミッション 3(発展): Apacheログの攻撃元IPのすべてのリクエストを時系列で並べ、攻撃のストーリー(偵察 → 攻撃 → 結果)を文章で説明してみましょう。どのIPがどの段階で何をしていたかを整理します。


トラブルシューティング

症状原因対処法
ログが検索結果に現れないインデックス化が失敗しているSettings → Data inputs → Files & Directories でステータスを確認
タイムスタンプが正しく解析されないソースタイプの設定が不適切Props.conf でタイムスタンプフォーマットを指定するか、UIから手動設定
SPLクエリが遅い時間範囲が広すぎるearliest / latest で検索範囲を絞る。index=sourcetype= を先頭に指定
Splunkが起動しないメモリ不足Splunkは最低4GBのRAMを推奨。VMのメモリを増やす
rex でフィールド抽出できない正規表現のパターンが誤っているSplunkの「Extract New Fields」(GUIでのフィールド抽出)を使って確認

Splunk自身のログを確認

sudo tail -50 /opt/splunk/var/log/splunk/splunkd.log

データ取り込みの状態を確認

sudo /opt/splunk/bin/splunk list inputstatus

インデックスの統計情報を確認

sudo /opt/splunk/bin/splunk list index

Splunkを再起動

sudo /opt/splunk/bin/splunk restart

Splunkを停止

sudo /opt/splunk/bin/splunk stop


理解度チェック

Splunk の SPL で `| stats count by clientip` を使った場合、何が得られますか?