サーバー運用者の危機対応

状況

おとりの改ざんでホストが隔離されたあと、通知の読み方、確認応答の意味(上限と縮退)、証拠の確かめ方、バックアップから戻して隔離を解く順番を学びます。

  • レベル: 実践
  • 約45分
  • 2026-11-12

#状況

ランサムウェアのおとりが反応したという通知が届きました

「ランサムウェア用おとりファイルが反応(ホスト隔離の直前)」と「ランサムウェア・カナリア発火」が、続けて届きました。あなたは、業務のデータを /srv に置いた Linux サーバーの当番です。

この講座は、通知が届いてから復旧するまでの判断と手順を扱います。検知の仕組みと設定は ランサムウェア に、自動で止める方針の決め方は 自動隔離の方針の設定 にあります。ここでは、使い捨ての VM で実際に起こし、その場で何を読み、どの順で動くかを確かめます。

扱う機能は、大量暗号化の検知、おとりファイルによる検知、通知の履歴、インシデントのタイムライン、封じ込め時の証拠の自動採取 です。

進める順番は、次のとおりです。

順番すること
1. 読む通知の履歴で、何が起き、何が止まったかを知る
2. 保つ確認応答で、上限の時間を過ぎても全面の隔離を保つ
3. 調べる書き手、証拠、壊れたファイルの数を確かめてから、書き手を終わらせる
4. 戻すバックアップを確かめてから戻し、最後に隔離を解く
5. 見守る同じ検知が、もう一度出ないかを見る

#起こす前に、戻せる状態を作る

本番でも、復旧の材料はバックアップだけです。演習でも、先にバックアップと、ファイルごとのハッシュの一覧を作ります。

ダミーのデータとバックアップを用意する

ファイルを作る操作です(変更を伴う操作です)。最後の章で消します。練習用の2つのファイルを作ります。make-data.sh は、平文のダミーのファイルを 300 個作ります。overwrite-demo.py は、指定したフォルダーの下のファイルを、同じ大きさのランダムなバイト列で上書きします。暗号化はせず、鍵もありません。

cd ~
cat > make-data.sh <<'S'
#!/bin/sh
# 練習用: 中身が平文のダミーのファイルを 300 個作る
mkdir -p /srv/appdata
for i in $(seq 1 300); do
  yes "order $i: dummy record for practice" | head -c 8192 > /srv/appdata/order_$i.csv
done
S
cat > overwrite-demo.py <<'S'
# 練習用: フォルダーの下のファイルを、同じ大きさのランダムなバイト列で上書きする
import os, sys, time
for root, dirs, files in os.walk(sys.argv[1]):
    for name in sorted(files):
        path = os.path.join(root, name)
        with open(path, "r+b") as f:
            f.write(os.urandom(os.path.getsize(path)))
        time.sleep(0.2)
S
sudo sh make-data.sh
sudo tar -czf /var/backups/appdata.tgz -C /srv appdata
cd /srv && sudo sha256sum appdata/* | sudo tee /var/backups/appdata.sha256 > /dev/null; cd ~
ls /srv/appdata | wc -l
sudo journalctl -u roamswitch-server -b | grep -oE 'following these folders.*|Total monitored canaries.*' | tail -2
sudo ls -A /srv
実行結果
300
following these folders roots=["/srv"]
Total monitored canaries: 16
.roamswitch_security_canary_do_not_delete.pdf
.roamswitch_security_canary_do_not_delete.xlsx
.roamswitch_security_canary_do_not_delete.zip
appdata

/srv は、大量暗号化の監視が見ているフォルダーです。おとりのファイルも3つあります。フォルダーの下を全部たどる書き手は、おとりにも当たります。

バックアップは /srv の外に置きました。監視の外ですが、同じディスクです。本番では、別のディスクか別のサーバーに置きます。

#起こして、通知を読む

上書きのスクリプトを、root で /srv に向けて動かします。サーバーで権限を取られたあとの動きを、まねたものです。

上書きを始めて、通知の履歴を読む

ホスト全体の通信を止める操作です(変更を伴う操作です)。SSH の保守用のポートは残りますが、必ず使い捨ての環境で試してください。元に戻す手順は、復旧の章にあります。

sudo setsid -f python3 overwrite-demo.py /srv > /dev/null 2>&1 < /dev/null
sleep 30
sudo roamswitch notifications
出力の抜粋(新しい順)
  2026-11-12T01:26:07.114715005+00:00
  ランサムウェア・カナリア発火
    🚨 カナリア(おとり)ファイルが改ざん / 暗号化書き込みされました
    ホスト: ubuntu (IP: 192.168.64.3)
    対象デコイ: /srv/.roamswitch_security_canary_do_not_delete.pdf
    疑わしいプロセス: python3 (PID: 1871)
    実行した封じ込め: プロセスを凍結し、ホストをAir-Gap隔離しました
    時刻: 2026-11-12 01:26:07
    プロセス: root / /usr/bin/python3.12 / コマンド: python3 overwrite-demo.py /srv (pid 1871)
    親プロセス: systemd / サービス: tart-guest-agent.service
    暗号化されたファイルの復号ツールを探す(公開されている場合だけ・無償): No More Ransom https://www.nomoreransom.org/ja/decryption-tools.html / 警察庁 https://www.npa.go.jp/bureau/cyber/countermeasures/ransom.html

  2026-11-12T01:26:07.029755454+00:00
  🚨 ランサムウェア用おとりファイルが反応(ホスト隔離の直前)
    おとりファイルの異常: 改ざん / 暗号化書き込み
    対象: /srv/.roamswitch_security_canary_do_not_delete.pdf
    疑わしいプロセス: python3(PID: 1871)
    この直後にホストを隔離します。結果は復旧後(または許可リスト経由)に別途通知します。
    プロセス: root / /usr/bin/python3.12 / コマンド: python3 overwrite-demo.py /srv (pid 1871)
    親プロセス: systemd / サービス: tart-guest-agent.service
    原因のプロセスが終わっても、この隔離は自動では解除しません。確認してから sudo roamswitch emergency-restore で解除してください。確認応答のないまま上限時間(既定60分)が過ぎると縮退に移り、縮退中は sudo roamswitch server ack で解除します。

通知の履歴は、新しいものが上です。下から読むと、起きた順になります。

  • 隔離の直前の通知(おとりファイルによる検知): PID 1871 が、おとりの .pdf を書き換えました。最後の行が、解除のしかたです。書き手が終わっても、自動では解けません
  • カナリア発火: 「実行した封じ込め」の行のとおり、書き手は凍結され、ホストは隔離されました。最後の行は、公開されている復号ツールの探し先です
  • プロセスの行: 2つの通知が、同じ PID とコマンドを指しています。同じ書き手による1つの出来事として扱えます

書き手は /srv の中を名前の順にたどるので、最初に .pdf のおとりを書き換えます。実行の記録(sudo roamswitch events search --pid 1871)では、書き手が動き始めたのは 01:26:06.809 です。おとりの改ざんの検知は 01:26:06.817 で、約 8 ミリ秒後でした。凍結は 01:26:07.030 です。時刻は UTC です。日本時間は 9 時間進めた 10:26 です。

2つの検知は、働き方が違います

大量暗号化の検知(大量暗号化の検知)は、既定では知らせるだけです(entropy_watch_freeze=false)。おとりの改ざんは、Server Edition では、ホストの隔離まで進みます。この演習では、書き手が appdata に進む前に凍結されたので、大量暗号化の通知は出ませんでした。同じ書き手を、おとりの無い /srv/appdata だけに向けると、大量暗号化の通知だけが来て、書き手は動き続けました。そのときは、通知の PID を自分で止めます(この講座の最後の判断を参照)。

#隔離を保つ

隔離の中でも、SSH の保守用のポート(既定は 22 番)には入れます。最初にすることは、隔離が働いていることと、書き手が止まっていることを確かめ、確認応答を返すことです。

止まっているものを確かめ、確認応答を返す

確認応答は、隔離の扱いを変える操作です(変更を伴う操作です)。隔離そのものは、復旧の章で解きます。

sudo roamswitch server ebpf | sed -n 5,7p
sudo roamswitch frozen list
P=$(pgrep -f '^python3 overwrite-demo.py /srv'); echo "P=$P"
ps -o pid,stat,cmd -p $P
curl -sS -m 5 -o /dev/null https://example.com; echo "curl rc=$?"
sudo roamswitch server ack
出力の抜粋
  現在の隔離状態: [隔離中: host_with_maintenance_ssh]
  隔離対象PID: [1871]
  保守用開放ポート: [22]

  PID 1871  python3
    理由: カナリアファイル改ざん
    凍結時刻: 2026-11-12T01:26:07.030528623+00:00

  誤検知だった場合: roamswitch frozen resume <PID>  (強制終了はしていないため、停止位置からそのまま再開します)

P=1871
    PID STAT CMD
   1871 Ts   python3 overwrite-demo.py /srv
curl: (28) Resolving timed out after 5002 milliseconds
curl rc=28
  ✓ 現在の緊急隔離(43秒経過)を確認しました。確認済みの間は自動で縮退・復旧せず、現在の隔離を維持します。
  解除するには: sudo roamswitch emergency-restore

読み方は次のとおりです。

  • host_with_maintenance_ssh: ホスト全体の隔離です。開いているのは 22 番だけです
  • STAT の T: 書き手は SIGSTOP で止まっています。終了はしていません。frozen resume をすると、続きから上書きを再開します
  • curl rc=28: 外への通信は止まっています
  • 確認応答の行: 「確認済みの間は自動で縮退・復旧せず」とあります。ここから先は、人が emergency-restore を実行するまで、全面の隔離が続きます
確認応答を、いつ返すか

おとりの改ざんは、確度の高い隔離です。書き手が終わっても、凍結のままでも、自動では解けません。確認応答が変えるのは、上限(isolation_hard_cap_secs、既定 3600 秒)を過ぎたあとの扱いです。

  • 調べるのに 1 時間を超えそう: 上限の前に確認応答を返します。上限を過ぎても、全面の隔離のまま保ちます
  • 確認応答を返さずに、上限を過ぎた: 縮退に移ります。縮退中の server ack は、隔離を解く操作です。まだ解かないなら、縮退中に server ack を打ちません
  • 自分の作業と分かった(誤検知): 確認応答は要りません。frozen resume <PID> で書き手を再開し、emergency-restore で隔離を解きます

確認応答を返さずに、凍結中の書き手を kill しても、この VM では隔離が続きました。

出力の抜粋(確認応答を返さずに、凍結中の書き手を kill して 7 分待ったとき)
P=2560
  現在の隔離状態: [隔離中: host_with_maintenance_ssh]
  隔離対象PID: [2560 (終了済み)]
curl: (28) Resolving timed out after 5002 milliseconds
curl rc=28

上限までの間は、確認応答のあるなしにかかわらず、隔離は続きます。

#書き手と、被害の範囲を調べる

隔離を保ったまま、何が、どこまで書き換えたかを確かめます。書き手を終わらせるのは、証拠を確かめたあとです。

証拠を読み、壊れたファイルを数えてから、書き手を終わらせる

読むだけの操作と、時系列の書き出しです(/root/incident.jsonl を作ります)。証拠バンドルのフォルダーは root だけが開けるので、一覧も sudo sh -c の中で取ります。

sudo roamswitch timeline | head -n 32
B=$(sudo sh -c 'ls -d /var/lib/roamswitch/incident-evidence/*/' | tail -1)
sudo roamswitch-incident-capture verify "$B"
sudo cat "$B/process/cmdline.txt"; echo
sudo cat "$B/process/fd_targets.txt"; echo
cd /srv && sudo sha256sum --quiet -c /var/backups/appdata.sha256 2>/dev/null | wc -l; cd ~
sudo roamswitch timeline --export /root/incident.jsonl
出力の抜粋
  2026-11-12T01:26:50.268817172+00:00  [Canary]  対応中
    server の隔離: 確認された(きっかけ: ランサムウェア用おとりファイルの改ざん、段階: 完全)
    実施した対応: 隔離に確認応答

  2026-11-12T01:26:06.817500072+00:00  [Canary]  対応中
    おとりのファイルが改ざんされた: /srv/.roamswitch_security_canary_do_not_delete.pdf(改ざん / 暗号化書き込み)
    プロセス: python3 (pid 1871)
    親プロセス系譜: systemd
    MITRE ATT&CK: T1486 (Data Encrypted for Impact)
    実施した対応: 封じ込めた(凍結または隔離)
    証拠バンドル: 20261112T012607Z-c5745d06-1879  manifest sha256:2656878eea2f7d46  (6 ファイル)

  └─ 2026-11-12T01:26:07.300535570+00:00  [Incident Capture]  対応中
       インシデント証拠バンドルを保存しました: /var/lib/roamswitch/incident-evidence/20261112T012607Z-c5745d06-1879
       プロセス: python3 (pid 1871)
       親プロセス系譜: systemd
       実施した対応: 証拠を保存
       証拠バンドル: 20261112T012607Z-c5745d06-1879  manifest sha256:2656878eea2f7d46  (6 ファイル)

  2026-11-12T01:25:31.038112055+00:00  [FIM]  記録のみ
    ログの改ざんの比較の基準を作り直した
    実施した対応: 記録のみ

整合性OK: バンドルはmanifest.jsonの記録と一致しています
アンカー: manifest.json は取得時の記録と一致しています
python3 overwrite-demo.py /srv
0 -> /dev/null
1 -> /dev/null
2 -> /dev/null
0
4件を /root/incident.jsonl にJSON Lines形式で書き出しました。

読み方は次のとおりです。

  • タイムライン(インシデントのタイムライン): おとりの改ざんと封じ込め、証拠の保存、確認応答が、1本の時系列に並びます。確認応答も記録に残ります。いちばん下の [FIM] の行は、デーモンの起動のときにログの比較の基準を作った記録で、「記録のみ」です。この出来事とは関係ありません
  • 証拠バンドル(封じ込め時の証拠の自動採取): 封じ込めのとき、凍結した書き手の /proc の情報(コマンドライン、開いていたファイル、親プロセスなど)を自動で保存していました。verify で、保存したときから変わっていないことを確かめます
  • 開いていたファイル(fd_targets.txt): 凍結の時点で開いていたのは /dev/null だけでした。書きかけのファイルは無かったことが分かります
  • 0: バックアップのハッシュと合わないファイルの数です。書き手は appdata に進む前に凍結されたので、300 個のどれも書き換えられていません
  • 親プロセス系譜: この演習では systemd です。本番で sshd や Web サーバーの名前が出ていれば、そこが侵入の経路の手がかりです

調べ終えたら、書き手を終わらせます。プロセスを終了する操作です(変更を伴う操作です)。終了したプロセスは、元に戻せません。

P=$(pgrep -f '^python3 overwrite-demo.py /srv'); echo "P=$P"
sudo kill -9 $P
sleep 420
pgrep -f '^python3 overwrite-demo.py /srv' || echo "no writer"
sudo roamswitch server ebpf | sed -n 5,6p
curl -sS -m 5 -o /dev/null https://example.com; echo "curl rc=$?"
出力の抜粋
P=1871
no writer
  現在の隔離状態: [隔離中: host_with_maintenance_ssh]
  隔離対象PID: [1871 (終了済み)]
curl: (28) Resolving timed out after 5002 milliseconds
curl rc=28

書き手は終わりましたが、隔離は続いています。PID の横に「終了済み」と出ます。

#ファイルを戻し、隔離を解き、見守る

戻すのは、原因を止めたあとです。順番は、バックアップを確かめる → 戻す → 確かめる → 隔離を解くです。隔離を解いてから戻すと、残っている書き手や経路に、戻したファイルをまた書き換えられるおそれがあります。

バックアップから戻し、隔離を解く

ファイルを上書きする操作です(変更を伴う操作です)。まず、別の場所に展開して、ハッシュの一覧と合うかを確かめます。

sudo rm -rf /var/tmp/restore-test; sudo mkdir /var/tmp/restore-test
sudo tar -xzf /var/backups/appdata.tgz -C /var/tmp/restore-test
cd /var/tmp/restore-test && sudo sha256sum --quiet -c /var/backups/appdata.sha256 && echo "backup: all 300 files match"; cd ~
sudo cp -a /var/tmp/restore-test/appdata/. /srv/appdata/
cd /srv && sudo sha256sum --quiet -c /var/backups/appdata.sha256 && echo "/srv/appdata: all 300 files match"; cd ~
実行結果
backup: all 300 files match
/srv/appdata: all 300 files match

バックアップが壊れていないことを先に確かめ、それから /srv/appdata に戻しました。戻したあとも、300 個すべてが元のハッシュと一致しました。この演習では書き換えは 0 個でしたが、本番では、どのファイルが書き換えられたかを先に知ることはできません。戻す手順は同じです。

次に、隔離を解きます。ホスト全体の通信を戻す操作です(変更を伴う操作です)。原因が消えたと確かめられないので、emergency-restore は RESTORE の入力を求めます。端末でないところ(パイプなど)から実行すると、「対話できない環境では、実行しません。」と出て、入力を受けずに終了コード 2 で終わります。最後の再起動で、ふだんの守りの規則を入れ直します。

sudo roamswitch emergency-restore
sudo roamswitch server restart
sleep 12
sudo head -c 32 /srv/.roamswitch_security_canary_do_not_delete.pdf; echo
sudo roamswitch notifications | grep -E '^  [^ ]' | sed -n 2,5p
curl -sS -m 5 -o /dev/null https://example.com; echo "curl rc=$?"
出力の抜粋
  現在の状態:
    隔離中(原因: ランサムウェア用おとりファイルの改ざん, 段階: 全面)

  ⚠️ 隔離の原因が解消したことを、確認できていません。この状態でネットワークを元に戻すと、原因が残っている場合、その影響を受けたまま通信が再開します。
  続けるには RESTORE と入力してください: RESTORE
  🔄 緊急遮断・隔離ルールを全解除し、ベースラインへ復旧中...
  (中略)
  次のファイアウォールのテーブルは、隔離ではないので残しました:
    - roamswitch_server: サーバーの受信の規則(ssh_ports・allowed_ports だけを通す、ふだんの防御)
  ✓ ネットワークを復旧しました。
  ポートスキャンの検知など、ここで外した規則は、再起動まで戻りません。戻すには: sudo systemctl restart roamswitch-server
  原因が残っている可能性があります(原因が消えたことは確かめられていません)。何が起きたかは roamswitch timeline で確かめてください。

  🔄 roamswitch-server サービスを再起動中...
  ✓ roamswitch-server サービスを正常に再起動しました。

%PDF-1.4 ROAMSWITCH_CANARY_INTEG
  2026-11-12T01:34:37.458317902+00:00
  【遅延送信】 📝 隔離インシデントを確認済みにしました
  2026-11-12T01:34:37.450850569+00:00
  【遅延送信】 ランサムウェア・カナリア発火
curl rc=0

プロンプトで RESTORE と入力すると、隔離の規則が外れ、「ネットワークを復旧しました」と出ます。ふだんの受信の規則(roamswitch_server)は、隔離ではないので残ります。おとりも元の中身に戻っています。最後の curl rc=0 で、外への通信が戻ったことが分かります。

通知の履歴 には、【遅延送信】 の付いた通知が並びました。隔離の間に外の通知先へ送れなかった通知を、解いたあとで送り直したものです。隔離の最中は、外の通知先に届いていないことがあります。当番に連絡するときは、通知先ではなく、サーバーの通知の履歴を正とします。

解いた直後は、同じ検知がもう一度出ないかを見ます。本番では、侵入の経路を塞ぎ、使われたアカウントの鍵やパスワードを替えたあとも、しばらく見続けます。

再発を見て、練習のファイルを消す

ファイルを消す操作です(変更を伴う操作です)。/root/incident.jsonl と証拠バンドルは、本番なら残します。

sleep 60
sudo journalctl -u roamswitch-server --since -75s | grep -c -e burst -e 'TAMPERED'
sudo roamswitch server ebpf | sed -n 5p
sudo rm -rf /srv/appdata /var/tmp/restore-test /var/backups/appdata.tgz /var/backups/appdata.sha256
rm -f ~/make-data.sh ~/overwrite-demo.py
実行結果
0
  現在の隔離状態: [隔離なし]

この 1 分間、大量暗号化とおとりの改ざんの記録は 0 件でした。隔離もありません。

おとりに当たらない暗号化だったとき

おとりの無いフォルダーだけが書き換えられると、届くのは大量暗号化の通知だけです。ホストは隔離されず、書き手も止まっていません。

  • 通知の PID に心当たりがない: すぐに sudo kill -STOP <PID> で止めます。止めれば、終了させずに証拠を残せます。そのあとは、この講座の「調べる」からと同じです
  • 心当たりがある(自分のバックアップ、アプリの正規の処理): 書き込みの量と場所がふだんどおりかを確かめ、記録して終えます
  • 毎回、人が止めるまで待てない: entropy_watch_freeze=true にして再起動します。次からは、書き手を自動で凍結します(自動隔離の方針の設定)
やってはいけないこと
  • 縮退に移ったあとで、隔離を保つつもりで server ack を打つ。縮退中の確認応答は、隔離を解きます
  • 凍結中の書き手を、frozen resume で再開する。誤検知と分かったとき以外は、上書きの続きが始まります
  • 隔離を解いてから、バックアップを戻す。経路が残っていれば、戻したファイルがまた書き換えられます
  • バックアップを確かめずに、上から戻す。壊れたバックアップで、残っていた正しいファイルまで上書きします

#見えない部分

この VM で確かめたことと、確かめた範囲
  • 凍結までに書かれた分は戻りません。この演習の書き手は、最初におとりに当たったので、appdata の書き換えは 0 個でした(日本語と英語の 2 回とも)。業務のファイルを先に書き換える書き手なら、おとりに当たるまでの分は書き換えられます。戻せるのは、バックアップがあるときだけです
  • 上限を過ぎたあとの縮退は、この講座では起こしていません。確かめたのは、書き手を終わらせても、確認応答があってもなくても、7 分のあいだ隔離が続いたことです。縮退は 自動隔離の方針の設定 で、上限を 120 秒にして試しています
  • 証拠バンドルのパケットキャプチャは取れていません。この VM には tshark が無く、バンドルの記録は skipped でした。保存されたのは、プロセスの情報だけです
  • 侵入の経路は、この演習にはありません。書き手は、VM の管理経路から直接動かしました。本番では、親プロセスと、ログイン・Web のログから調べます
  • 演習の書き手は、ランダムなバイト列で上書きするだけです。暗号文を別のファイルに書いて元を消す形、名前を変えて被せる形の見え方は、ランサムウェア で扱います
確認問題

おとりの改ざんでホストが隔離され、書き手は凍結されています。調べ終わるまで 2 時間かかりそうです。全面の隔離のまま保つには、どうしますか

解説を見る

確認応答のない隔離は、上限(既定 60 分)を過ぎると縮退に移ります。全面のときの確認応答は、隔離を保ちます。縮退中の確認応答は、隔離を解きます。

確認問題

書き手を止め、証拠を確かめました。次の順番で正しいものはどれですか

解説を見る

戻す前にバックアップを確かめ、戻したあとに結果を確かめます。隔離を解くのは最後です。

#次に学ぶこと

扱う機能

対応する攻撃手法 (ATT&CK): T1486

確認した内容

2026-11-12に確認しました。対象は Linux 1.17.39 です。公開版 1.17.39 の入った使い捨ての Ubuntu 24.04 の VM で、root の書き手で /srv を上書きし、おとりの改ざんの通知・凍結と隔離、確認応答、証拠バンドルの検証、書き手を kill して 7 分待つこと(確認応答のあるとき・ないとき)、バックアップからの復元と端末での RESTORE の入力による解除と curl での確認を、日本語と英語で別の VM で実行し、おとりの無いフォルダーだけに向けたときの大量暗号化の通知も確かめました。

コマンドの出力は、製品の版や環境によって変わります。違いが出たら、まず製品の版を確かめてください。