#入り込んだあとに、攻撃者が残すもの
サーバーに入り込んだ攻撃者は、次も入れるように居座りの仕掛けを残します。root を取ったら、それを保つ手も打ちます。最後に、ログを消して痕跡を隠します。よく使われる手口と、Server Edition で見張る機能は次のとおりです。
| 手口 | 例 | 見張る機能 |
|---|---|---|
| 鍵を足して、パスワードなしで戻る | /root/.ssh/authorized_keys に自分の公開鍵を書く | 重要システムファイルの改ざん監視 |
| 権限の設定を書き換える | /etc/sudoers.d/ にファイルを足す | 同上 |
| 定期実行や自動起動に登録する | /etc/cron.d/、/etc/systemd/system/ にファイルを置く | 同上 |
| root で動くプログラムを残す | 自分のプログラムに SUID を付ける | SUID・SGID の変更の監視 |
| 痕跡を消す | /var/log/auth.log を空にする | ログ消去の監視 |
どれも、root を取られたあとの動きです。だから、この講座の機能は止めずに知らせます。止める相手がもう root を持っているためです。最後の章では、root を取らせにくくする設定(カーネルの堅牢化 と 権限昇格の通り道になるカーネルモジュールの点検)を見ます。
この講座の演習は、重要なファイルやログを、わざと書き換えます。使い捨ての VM で試してください。演習の VM の時計は UTC です。日本時間は 9 時間足して読みます。
#重要なファイルの書き換えを見つける
重要システムファイルの改ざん監視 は、sudoers、PAM、sshd の設定、cron、systemd のユニット、各アカウントの authorized_keys などのハッシュを記録します。書き込みと、見張るフォルダーへの新しいファイルは、その場で見ます(fanotify)。さらに、定期の検査で全体を比べ直します。
重要なファイルを書き換える操作です(変更を伴う操作です)。最後に元に戻します。
この演習では、同じ VM の中から 127.0.0.1 に SSH でログインして試しました。admin は、自分のアカウント名に置き換えます。足す鍵は、形だけの無効なダミーです。
ssh-keygen -q -t ed25519 -N "" -f ~/.ssh/lab_key
cat ~/.ssh/lab_key.pub >> ~/.ssh/authorized_keys
ssh -o StrictHostKeyChecking=accept-new -i ~/.ssh/lab_key admin@127.0.0.1 \
'echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEXAMPLE lab@example" | sudo tee -a /root/.ssh/authorized_keys >/dev/null'
sleep 5
sudo roamswitch notifications | grep -A8 FIM | head -9 クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.8)
ハッシュが一致しない重要システムファイル:
/root/.ssh/authorized_keys: 内容の変更
プロセス: root(ログインしたアカウント: admin) / /usr/bin/tee / コマンド: tee -a /root/.ssh/authorized_keys (pid 26094)
SSH ログイン: 127.0.0.1:37356 から admin が 2026-11-12 01:33:38 にログインしたセッションです(認証: publickey, 鍵 SHA256:rkBIL270U06lSAVL6PeFRbgM29moyiChfjIWkAVaSBA)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 01:33:39書き込んだ直後に、通知が出ました。種類は「内容の変更」です。見るところは 3 つです。
- プロセス: 書き込んだのは root の
teeです。ログインしたアカウント(admin)も出ます - SSH ログイン: どこから(
127.0.0.1:37356)、いつ、どの鍵でログインしたセッションかが出ます。外から入られたときは、ここに相手のアドレスが出ます - 2 行目のコマンド: 自分の
authorized_keysに鍵を足した操作も、別の通知になりました(抜粋では省いています)。各アカウントの鍵も見ているためです
ログインの情報は、fim_intrusion_context_enabled(既定 true)が付けます。/proc、実行の記録、logind から読むだけで、どこにも送りません(設定ファイルの注記)。
通知が来たら、何が変わったかを fim verify で確かめます。元に戻したら、もう一度確かめます。
sudo roamswitch fim verify
sudo sed -i '/lab@example/d' /root/.ssh/authorized_keys
sudo roamswitch fim verify
sudo roamswitch fim update 🔍 最重要システムファイルの整合性を検証中... (90 件)
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /root/.ssh/authorized_keys
[内容の変更] /home/admin/.ssh/authorized_keys
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。
🔍 最重要システムファイルの整合性を検証中... (90 件)
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /home/admin/.ssh/authorized_keys
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。
📝 現在のシステムファイルからベースラインDBを再作成中...
✓ ベースラインDBを正常に更新・署名保存しました。 (90 件記録)
✓ SUID / SGID ファイルの基準を更新しました。 (20 件記録)root の鍵の行を消すと、/root/.ssh/authorized_keys は一覧から消えました。基準と同じ中身に戻ったためです。残った /home/admin/.ssh/authorized_keys は、自分で足した鍵なので、fim update で基準に入れました。
fim update は、その時点のすべての状態を正しいものとして基準にします。攻撃者が足した鍵が残っていれば、それも正しいものになり、以後は知らせません。fim verify の一覧を1行ずつ確かめて、残すものだけになってから実行します。
新しく置かれたファイル
cron やユニットのファイルを新しく置く手口も、その場で見つかります。/etc/cron.d・/etc/sudoers.d・/etc/systemd/system などの見張るフォルダーに、ファイルができた時点で知らせます。
ファイルを置く操作です(変更を伴う操作です)。前の演習の鍵で SSH でログインし、1 つは tee で書き、もう 1 つは /tmp で作ってから mv で移します。中身は、何もしない /usr/bin/true を動かすだけです。
ssh -i ~/.ssh/lab_key admin@127.0.0.1 \
'echo "*/5 * * * * root /usr/bin/true" | sudo tee /etc/cron.d/lab-persist >/dev/null'
ssh -i ~/.ssh/lab_key admin@127.0.0.1 \
'echo "*/5 * * * * root /usr/bin/true" > /tmp/lab-mv && sudo mv /tmp/lab-mv /etc/cron.d/lab-mv'
sleep 5
sudo roamswitch notifications | grep -A6 FIM | head -14 クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.8)
ハッシュが一致しない重要システムファイル:
/etc/cron.d/lab-mv: 新しいファイル
ログインの経路は調べられませんでした(別の場所から移動(mv)で置かれたため、書いたプロセスは特定できません)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 01:33:56
--
クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.8)
ハッシュが一致しない重要システムファイル:
/etc/cron.d/lab-persist: 新しいファイル
プロセス: root(ログインしたアカウント: admin) / /usr/bin/tee / コマンド: tee /etc/cron.d/lab-persist (pid 26455)
SSH ログイン: 127.0.0.1:37324 から admin が 2026-11-12 01:33:55 にログインしたセッションです(認証: publickey, 鍵 SHA256:rkBIL270U06lSAVL6PeFRbgM29moyiChfjIWkAVaSBA)2 つとも「新しいファイル」として、置いた 1 秒後に出ました。tee で書いたほうは、書いたプロセスと SSH のログインまで分かります。mv で移したほうは、書いたプロセスが分かりません。だれが置いたかは、ファイルの時刻と、last や journalctl のログインの記録を突き合わせて調べます。
同じ VM で、lab-persist を消して、同じ中身で置き直しました。置き直したときも、もう一度「新しいファイル」として通知が出ました。消して置き直す手口も、見落としません。
元に戻します。ファイルを消して、確かめます。
sudo rm /etc/cron.d/lab-persist /etc/cron.d/lab-mv
sudo roamswitch fim verify 🔍 最重要システムファイルの整合性を検証中... (90 件)
✓ 改ざんは検知されませんでした。すべて正常です。 (90 ファイルを監視中)
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)#SUID の付いたファイルを見つける
SUID が付いたプログラムは、実行した人ではなく、持ち主の権限で動きます。持ち主が root なら、だれが実行しても root です。root を取った攻撃者は、自分用の入り口として、これを残します。SUID・SGID の変更の監視 は、SUID と SGID が付いたファイルの一覧を基準にして、追加と変更を知らせます。
root で動くファイルを作る操作です(変更を伴う操作です)。最後に消します。中身は、自分の ID を表示するだけの id の写しです。
sudo cp /usr/bin/id /usr/local/bin/lab-id
sudo chmod u+s /usr/local/bin/lab-id
/usr/local/bin/lab-id
sleep 5
sudo roamswitch notifications | grep -A10 SUID | head -11
sudo roamswitch fim verifyuid=1000(admin) gid=109(admin) euid=0(root) groups=109(admin)
SUID/SGIDファイルの追加・変更を検知 (1 件)
ホスト: ubuntu (IP: 192.168.64.8)
SUID または SGID が付いた実行ファイルに、次の変化がありました:
/usr/local/bin/lab-id に SUID/SGID が付きました(新規、または後から付与。モード 4755、所有者 UID 0、どのパッケージにも属していません)
SUID が付いた実行ファイルは、実行した人ではなく持ち主(多くは root)の権限で動きます。攻撃者が root を保つために使う手口です。
確認: `ls -l` で持ち主と更新時刻を、`last` で直近のログインを見てください。
正規の変更だと分かっているとき: `sudo roamswitch fim update` で現在の状態を基準にします。
時刻: 2026-11-12 01:34:19
プロセス: root / /usr/bin/chmod / コマンド: chmod u+s /usr/local/bin/lab-id (pid 26651)
親プロセス: sudo ← dash ← tart-guest-agent ← systemd / サービス: tart-guest-agent.service
🔍 最重要システムファイルの整合性を検証中... (90 件)
✓ 改ざんは検知されませんでした。すべて正常です。 (90 ファイルを監視中)
🔍 SUID / SGID ファイルの一覧を確認中...
🚨 SUID / SGID ファイルの追加・変更が見つかりました!
[SUID/SGID の追加] /usr/local/bin/lab-id (4755)1 行目を見てください。一般の admin が実行したのに、euid=0(root) です。これが、SUID が居座りに使われる理由です。
通知には、chmod を実行したプロセスと、その親が出ています。モードの変更は、その場で見ているためです(fanotify)。全体の一覧も、suid_watch_interval_secs(既定 600 秒)ごとに作り直して比べます。「どのパッケージにも属していません」は大事な手がかりです。パッケージの更新で説明できる変更は、知らせずに基準に入ります(設定ファイルの注記)。
元に戻します。
sudo rm /usr/local/bin/lab-id
sudo roamswitch fim verify | tail -2 ✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)正しい変更だと分かっている SUID のファイルは、fim update で基準に入れます。入れるまで、fim verify は失敗として出し続けます。
#ログの消去を見つける
ログは、ふだんから書き足されて変わります。だから、ハッシュを比べる FIM では、消されたことが分かりません。ログ消去の監視 は、auth.log、syslog、audit.log、wtmp などを 30 秒ごとに見て、小さくなった、消えた、別のファイルに入れ替わったことを知らせます。ログのローテーションで説明できる変化は除きます。
ログを消す操作です(変更を伴う操作です)。先に写しを取って、最後に戻します。
sudo cp -p /var/log/auth.log /root/auth.log.bak
sudo truncate -s 0 /var/log/auth.log
sleep 35
sudo roamswitch notifications | grep -A8 'ログの消去' | head -9 ログの消去の疑いを検知 (1 件)
ホスト: ubuntu (IP: 192.168.64.8)
次のログが、ログローテーションでは説明できない形で変わりました:
/var/log/auth.log が小さくなりました(63186 バイト → 99 バイト)
攻撃者が痕跡を消した可能性があります。
確認: `last` と `sudo journalctl -u ssh` で直近のログインを、`sudo roamswitch fim verify` で重要ファイルと SUID ファイルの変化を見てください。
時刻: 2026-11-12 01:34:50
変更したプロセスは特定できません(ファイルの状態を定期的に比べて見つけたため)空にしてから 30 秒以内に、通知が出ました。99 バイトは、空にしたあとに書き足された分です。最後の行のとおり、だれが消したかは分かりません。ファイルの大きさを定期的に比べて見つけるためです。
写しを戻します。
sudo cp /root/auth.log.bak /var/log/auth.log
sudo rm /root/auth.log.bak同じ VM で、ほかの消し方と、正しい作業も試しました。
sudo sed -i '/127.0.0.1/d' /var/log/auth.logで行だけを消すと、「別のファイル(inode が違う)に差し替えられ、小さくなりました」と知らせました。sed -iは、新しいファイルを作って置き換えるためです- 同じファイルの変化が、前の通知から 5 分以内に続いたときは、すぐには知らせません。5 分たってから、「前の通知のあと、同じファイルでさらに 1 回起きました」のように、回数を入れた 1 件で知らせました。保留のあいだに
sudo roamswitch server restartを挟んでも、この 1 件は出ました sudo logrotate -f /etc/logrotate.confでローテーションすると、auth.logは新しい小さなファイル(40 秒後に 99 バイト)になりましたが、通知は出ませんでした。古い中身はauth.log.1に残っていて、ローテーションで説明できるためです
消されたあとでも、手がかりは残ります。通知の「確認」にあるとおり、last(wtmp から読むログインの記録)と journalctl を見ます。続けて sudo roamswitch fim verify で、鍵や SUID が足されていないかを確かめます。ログを消す前に、居座りの仕掛けが置かれていることが多いからです。
#足がかりを減らす
ここまでの機能は、root を取られたあとに知らせるものでした。カーネルの堅牢化 は、その前の段階で、権限を上げる足がかりを減らします。Server Edition のデーモンは、起動するたびに、カーネルの設定(sysctl)を書き込みます。
一般のアカウント(admin)で実行します。何も変更しません。
sysctl kernel.yama.ptrace_scope kernel.unprivileged_userns_clone kernel.unprivileged_bpf_disabled
strace -o /dev/null true 2>&1; echo "strace: $?"
unshare -U true 2>&1; echo "unshare: $?"
sudo roamswitch server config get harden_userns_enabledkernel.yama.ptrace_scope = 2
kernel.unprivileged_userns_clone = 0
kernel.unprivileged_bpf_disabled = 1
strace: test_ptrace_get_syscall_info: PTRACE_TRACEME: Operation not permitted
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace: 1
unshare: unshare failed: Operation not permitted
unshare: 1
true3 つの設定は、次の意味です。
| 設定 | 値 | 効き目 |
|---|---|---|
kernel.yama.ptrace_scope | 2 | ほかのプロセスの中身を読む ptrace を、管理者だけにする。一般のアカウントは、自分の子のプロセスも追えない |
kernel.unprivileged_userns_clone | 0 | 一般のアカウントが、ユーザー名前空間を作れない |
kernel.unprivileged_bpf_disabled | 1 | 一般のアカウントが、eBPF のプログラムを読み込めない |
比べるため、デーモンを一度も動かしていない、起動したばかりの VM でも見ました。そのときの値は、ptrace_scope が 1、unprivileged_userns_clone が 1、unprivileged_bpf_disabled が 2 でした(Ubuntu 24.04 の既定)。strace -o /dev/null true と unshare -U true は、どちらも終了コード 0 で通りました。RoamSwitch は /etc/sysctl.d/ にファイルを置かず、起動のたびに書き込みます。
ユーザー名前空間を禁じると、root を使わないコンテナ(Podman rootless など)や、サンドボックスで動くアプリが動かなくなります(設定ファイルの注記)。それらを使うなら、sudo roamswitch server config set harden_userns_enabled false にします。
ただし、切っても、すぐには元に戻りません。false にすると、「非特権ユーザー名前空間の制限は、OS を再起動したときに外れます」と出ます。
同じ VM で server restart しても、unprivileged_userns_clone は 0 のままで、unshare -U true は失敗しました。OS を再起動したあとに 1 になり、unshare が通りました。true に戻して server restart すると、すぐ 0 に戻りました。
設定ファイルの注記のとおり、根本の対策は、修正済みのカーネルに更新することです。
権限昇格の通り道になるカーネルモジュールの点検 は、2026 年のローカル権限昇格で使われたカーネルモジュールを、読み込める状態かどうか調べます。
調べるだけなら、何も変更しません。--apply と --remove は、/etc/modprobe.d/ にファイルを書く、変更を伴う操作です。
roamswitch kernel-modules kernel 7.0.0-42-generic
非特権のユーザー名前空間: 使えない(esp4・esp6・act_pedit への経路は閉じています)
algif_aead 読み込み禁止済み [Copy Fail / CVE-2026-31431]
esp4 未使用・要求されれば読み込まれます [Dirty Frag / Fragnesia / CVE-2026-43284]
esp6 未使用・要求されれば読み込まれます [Dirty Frag / Fragnesia / CVE-2026-43284]
rxrpc 未使用・要求されれば読み込まれます [Dirty Frag / DirtyDecrypt / CVE-2026-43500]
act_pedit 未使用・要求されれば読み込まれます [act_pedit page-cache write / CVE-2026-46331]2 行目は、前の演習のユーザー名前空間の設定とつながっています。名前空間が使えないので、esp4、esp6、act_pedit への経路は閉じている、という判定です。algif_aead は、この VM では Ubuntu 自身の /etc/modprobe.d/disable-algif_aead.conf が、すでに止めていました。
使っていない esp4 の読み込みを止めて、本当に読み込めないかを確かめます。
sudo roamswitch kernel-modules --apply esp4
cat /etc/modprobe.d/roamswitch-kernel-module-surface.conf
sudo modprobe esp4 2>&1; echo "modprobe: $?"書き込みました: /etc/modprobe.d/roamswitch-kernel-module-surface.conf (esp4)
esp4 読み込み禁止済み [Dirty Frag / Fragnesia / CVE-2026-43284]
# Written by RoamSwitch (roamswitch kernel-modules --apply). Stops these kernel modules from
# being loaded on demand. Undo: roamswitch kernel-modules --remove (or delete this file).
install esp4 /bin/false
modprobe: ERROR: ../libkmod/libkmod-module.c:1084 command_do() Error running install command '/bin/false' for module esp4: retcode 1
modprobe: ERROR: could not insert 'esp4': Invalid argument
modprobe: 1元に戻します。設定ファイルが消えて、esp4 は読み込める状態に戻ります。
sudo roamswitch kernel-modules --remove
roamswitch kernel-modules | grep '^ esp4'設定ファイルを削除しました。
esp4 未使用・要求されれば読み込まれます [Dirty Frag / Fragnesia / CVE-2026-43284]IPsec の VPN(strongSwan など)で使っている esp4・esp6 は、自動で対象から外れます(コマンドの出力の注記)。このコマンドは、カーネルが修正済みかどうかは見ません。
#見えない部分
使い捨ての Ubuntu 24.04 の VM で確かめた範囲では、次のようになります。
- アカウントごとの crontab と
~/.bashrcは、Server の FIM の対象外です。adminでcrontab -と~/.bashrcへの追記をしました。fim verifyは「すべて正常」で、FIM の通知も増えませんでした。見ているのは/etc/cron.d/などのシステム全体の場所です mvで置かれたファイルは、書いたプロセスが分かりません。見張るフォルダーに置かれたことは、その場で分かります。だれが書いたかは、ファイルの時刻とログインの記録から調べます- ログの消去も、書いたプロセスは分かりません。30 秒ごとの比較のため、その間に消して同じ大きさまで埋め戻されると、
wtmp・btmp以外のログでは分かりません(コードの注記で確認) - 知らせるだけで、止めません。この講座の通知のあと、プロセスやネットワークの隔離は起きませんでした。root を取られたあとの対応は、人が行います
- カーネルの設定は、すべての権限昇格を防ぎません。この VM でも、
sudo strace -o /dev/null trueは通りました。管理者の権限を持つプロセスには効きません。根本の対策は、カーネルの更新です
sudo roamswitch fim verify に [新しいファイル] /etc/cron.d/backup-sync が出ました。心当たりがありません。最初にすることはどれですか
解説を見る
fim updateは、その時点の状態をすべて正しいものにします。攻撃者のファイルも正しいものになり、以後は知らせません。通知に書いたプロセスが出ていればそれを、mvで置かれて出ていなければ、中身と時刻から、だれがいつ置いたかをたどります。消すのは、ほかの仕掛け(鍵、SUID)がないかを確かめてからです。
rootless のコンテナを使うため、harden_userns_enabled を false にして sudo roamswitch server restart を実行しました。unshare -U true はどうなりますか
解説を見る
デーモンは、起動するときに禁止の値を書き込みます。
falseにすると書き込まなくなりますが、すでに書いた値は戻しません。同じ VM では、OS を再起動したあとに通るようになりました。
#次に学ぶこと
- FIM の通知を SIEM や syslog に転送して受け取る手順は、通知と転送の設定 で扱います
- 封じ込めが働いたあとの調べ方は、封じ込めが働いたあとの最初の1時間 で学べます
- ログが消されたときの手順は、「ログが消された・書き換えられたとき」(準備中)で扱います
- 鍵を足すために使われやすい SSH の入り口の守り方は、SSH の保護の設定 で扱います
- 設定の全項目は、Linux Server の運用マニュアル にあります
対応する攻撃手法 (ATT&CK): T1098.004 T1548.003 T1548.001 T1685.006 T1055
2026-11-12に確認しました。対象は Linux 1.17.39 です。使い捨ての Ubuntu 24.04 の VM(公開版 1.17.39)で、同じ VM への SSH ログインで鍵・cron・SUID・ログの消去を起こし、消して置き直す形、5 分以内の繰り返しとその保留中のデーモンの再起動、sed -i と logrotate、カーネルの設定とモジュール、harden_userns_enabled を切ったあとの OS の再起動を、日本語と英語で実行して確かめました。
コマンドの出力は、製品の版や環境によって変わります。違いが出たら、まず製品の版を確かめてください。