#攻撃者は、SSH をどう使うか
SSH は、サーバーを管理する入り口です。攻撃者にとっても、同じ入り口になります。入ったあとの動きは、だいたい次の4つです。
| 段階 | 攻撃者がすること | この講座で見るもの |
|---|---|---|
| 入る | 推測したパスワードでログインする | SSH 総当たりの検知と遮断 の「総当たりのあとにログインが成功」の通知 |
| 居座る | authorized_keys に自分の鍵を足す | 重要システムファイルの改ざん監視 の通知と、書き換えたセッション |
| 奥へ通す | SSH のトンネルを張る、トンネルの道具を動かす | SSH のトンネルの検知 の通知、roamswitch ports -a、プロセス実行の記録と攻撃手口の検知 の EXR-010 |
| 入り口を広げる | root のログインや、パスワードなしの sudo を残す | SSH と sudo の設定の診断 |
総当たりを遮断する設定と、接続元を許可リストに限る設定は、SSH の保護の設定 で扱いました。この講座は、その先を扱います。遮断のしきい値に届かずに入られたあと、何が見えて、何が見えないかです。
この講座では、sshd と sudo の設定を、わざと弱くします。実機では試さないでください。この講座の VM は tart exec で操作するので、SSH の設定を誤っても作業を続けられます。
#練習の場を用意する
外からの攻撃者に見立てるため、VM の中にネットワーク名前空間を作ります。手順は SSH の保護の設定 と同じです。10.99.0.2 と 10.99.0.3 が外の接続元、10.99.0.1 が VM の側です。
ユーザーを作り、ネットワークの設定を足す操作です(変更を伴う操作です)。パスワードは練習用のダミーです。
sudo useradd -m -s /bin/bash labuser
echo 'labuser:Practice-Pass-123' | sudo chpasswd
sudo install -d -m 700 -o labuser -g labuser /home/labuser/.ssh
sudo apt install -y sshpass
sudo ip netns add outside
sudo ip link add veth-host type veth peer name veth-out
sudo ip link set veth-out netns outside
sudo ip addr add 10.99.0.1/24 dev veth-host
sudo ip link set veth-host up
sudo ip netns exec outside ip addr add 10.99.0.2/24 dev veth-out
sudo ip netns exec outside ip addr add 10.99.0.3/24 dev veth-out
sudo ip netns exec outside ip link set veth-out up
sudo roamswitch server restart
sudo roamswitch bans | sed -n 5,6p ✓ roamswitch-server サービスを正常に再起動しました。
状態 : 検知のみ(遮断しない)
理由 : fail2ban が SSH を防御しているため、遮断はそちらに任せています(ssh_guard_yield_to_fail2ban=true)。この VM では fail2ban が sshd を見ているので、RoamSwitch のガードは「検知のみ」です。この講座では、fail2ban は止めません。これから見る通知は、検知のみの状態でも出ます。
元に戻す手順は、最後の演習の終わりにまとめてあります。
#推測されたパスワードで入られる
遮断は、失敗が ssh_guard_max_failures(既定 6 回)に届いたときです。攻撃者が、それより少ない回数で当てたら、遮断は起きません。ガードは、その代わりに「失敗のあとの成功」を知らせます。
コードでは、窓の時間(ssh_guard_window_secs、既定 600 秒)のうちに、しきい値の半分(既定なら 3 回)以上失敗した接続元が、そのあとログインに成功すると知らせます。
10.99.0.2 から、間違ったパスワードで 3 回試します。4 回目に正しいパスワードで入り、攻撃者の鍵を authorized_keys に足します。鍵は、この場で作る練習用のものです。
F="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1 -o LogLevel=ERROR -o ConnectTimeout=5"
ssh-keygen -q -t ed25519 -N "" -C lab-dummy-key -f /tmp/lab_key
for p in wrong-1 wrong-2 wrong-3; do sudo ip netns exec outside sshpass -p $p ssh $F -b 10.99.0.2 labuser@10.99.0.1 true; done
sudo ip netns exec outside sshpass -p Practice-Pass-123 ssh $F -b 10.99.0.2 labuser@10.99.0.1 "echo logged in from \$SSH_CLIENT; sleep 2; echo '$(cat /tmp/lab_key.pub)' >> ~/.ssh/authorized_keys; sleep 3; true"labuser@10.99.0.1: Permission denied (publickey,password).
labuser@10.99.0.1: Permission denied (publickey,password).
labuser@10.99.0.1: Permission denied (publickey,password).
logged in from 10.99.0.2 58019 22通知の履歴を見ます。新しいものが上です。
sudo roamswitch notifications | head -34 2026-11-12T02:32:38.874191964+00:00
クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.5)
ハッシュが一致しない重要システムファイル:
/home/labuser/.ssh/authorized_keys: 新しいファイル
プロセス: labuser / /usr/bin/bash / コマンド: bash -c echo logged in from $SSH_CLIENT; sleep 2; echo 'ssh-ed25519 SHA256:KQPtaxW8VtuW6Dpd188A+Xk78Q3T8jGiz/l39e6vdBw lab-dummy-key' >> ~/.ssh/authorized_keys;… (pid 1711)
SSH ログイン: 10.99.0.2:58019 から labuser が 2026-11-12 02:32:36 にログインしたセッションです(認証: password)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 02:32:38
2026-11-12T02:32:36.558087448+00:00
【重大】SSH 総当たりのあとにログインが成功: 10.99.0.2
ホスト: ubuntu (IP: 192.168.64.5)
接続元: 10.99.0.2
ログインしたアカウント: labuser
認証方法: password
その前の失敗: 3 回
パスワードが推測された可能性があります。心当たりがなければ、すぐに確認してください。
・who や last で今のセッションを確かめ、不審なら loginctl terminate-session で切ってください
・そのアカウントのパスワードを変え、鍵認証だけにしてください(PasswordAuthentication no)
・authorized_keys、cron、systemd のユーザーサービスに、見覚えのない変更がないか確かめてください
セッションは切っていません。
時刻: 2026-11-12 02:32:362つの通知が出ました。下が先です。
- 総当たりのあとにログインが成功: 3 回の失敗のあとの成功を、重大として知らせました。時刻は UTC で、日本時間では 11:32:36 です
- FIM の通知: 書き込みの直後に、
authorized_keysが足されたことを知らせました。書いたコマンドと、そのプロセスが属する SSH のログイン(接続元・ポート・時刻・認証方法)が付いています - セッションは切っていません: 通知のあとも、攻撃者のセッションは続きます。切るかどうかは、人が決めます
- 遮断しない接続元: 開いている SSH のセッションの接続元は、SSH ガードが遮断しません。自分の作業を締め出さないためです。その接続元が攻撃者のものでも同じなので、セッションを切るのは人です
コマンドの中の公開鍵は、SHA256: で始まる指紋にまとめて出ます。長いコマンドは、途中で … に切れます。
まず、そのログインが自分かどうかを確かめます。
- 自分だった(パスワードを打ち間違えただけ): 鍵でのログインに切り替えます。この講座の最後の演習で、パスワードのログインを止めます
- 心当たりがない: パスワードが知られています。セッションを切り、パスワードを変えます。同じ時刻の前後に、FIM の通知が出ていないかも見ます。上の例のように、入った直後に鍵を置かれていることがあります
どちらか分からないときは、心当たりがないほうとして扱います。
#置かれた鍵を見つける
パスワードを変えても、置かれた鍵は残ります。攻撃者は、次から鍵で入れます。鍵のログインには失敗が要らないので、「総当たりのあとにログインが成功」の通知も出ません。
攻撃者が、別の接続元 10.99.0.3 から、置いた鍵で入ります。入ったあと、もう一度 authorized_keys を書き換えます。
K="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=5 -o BatchMode=yes -i /tmp/lab_key"
sudo ip netns exec outside ssh $K -b 10.99.0.3 labuser@10.99.0.1 'echo key login from $SSH_CLIENT; sleep 2; echo "# lab note" >> ~/.ssh/authorized_keys; sleep 3; true'
sudo roamswitch notifications | head -14key login from 10.99.0.3 52049 22
2026-11-12T02:32:56.342263139+00:00
クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.5)
ハッシュが一致しない重要システムファイル:
/home/labuser/.ssh/authorized_keys: 新しいファイル
プロセス: labuser / /usr/bin/bash / コマンド: bash -c echo key login from $SSH_CLIENT; sleep 2; echo "# lab note" >> ~/.ssh/authorized_keys; sleep 3; true (pid 1915)
SSH ログイン: 10.99.0.3:52049 から labuser が 2026-11-12 02:32:54 にログインしたセッションです(認証: publickey, 鍵 SHA256:KQPtaxW8VtuW6Dpd188A+Xk78Q3T8jGiz/l39e6vdBw)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 02:32:56今度は、認証が publickey で、鍵の指紋が付いています。「新しいファイル」のままなのは、基準(ベースライン)にこのファイルが無いためです。基準と比べるので、2回目の書き換えも「新しいファイル」と出ます。
指紋が、どの鍵のものかを確かめます。sshd のログにも、同じ指紋が残っています。
ssh-keygen -lf /tmp/lab_key.pub
sudo journalctl -u ssh --since "-3min" --no-pager | grep Accepted256 SHA256:KQPtaxW8VtuW6Dpd188A+Xk78Q3T8jGiz/l39e6vdBw lab-dummy-key (ED25519)
Nov 12 02:32:36 ubuntu sshd[1571]: Accepted password for labuser from 10.99.0.2 port 58019 ssh2
Nov 12 02:32:54 ubuntu sshd[1852]: Accepted publickey for labuser from 10.99.0.3 port 52049 ssh2: ED25519 SHA256:KQPtaxW8VtuW6Dpd188A+Xk78Q3T8jGiz/l39e6vdBw実際の調査では、/tmp/lab_key.pub の代わりに ssh-keygen -lf ~labuser/.ssh/authorized_keys で、ファイルにある鍵の指紋を一覧にします。ログの指紋と合う行が、使われた鍵です。
何を見張っているかは、detection-coverage で確かめられます。
sudo roamswitch detection-coverage --server | grep -A2 T1098.004 🟡 T1098.004 Account Manipulation: SSH Authorized Keys [一部] 稼働中
担当: criticalPathFim
見えない部分: 見ているのは、ログインできるアカウントと root の .ssh にある authorized_keys / authorized_keys2 だけです。sshd の AuthorizedKeysFile で別の場所にした鍵や、AuthorizedKeysCommand で渡す鍵は見ていません。鍵を取り除きます(変更を伴う操作です)。fim verify で変わったファイルを確かめ、消したあとにもう一度確かめます。
sudo roamswitch fim verify
sudo rm /home/labuser/.ssh/authorized_keys
sudo roamswitch fim verify 🔍 最重要システムファイルの整合性を検証中... (93 件)
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /etc/passwd
[内容の変更] /etc/gshadow
[新しいファイル] /home/labuser/.ssh/authorized_keys
[内容の変更] /etc/shadow
[内容の変更] /etc/group
このうち 4 件は、2026-11-12 02:32 のパッケージの更新で説明できなかったため、基準に取り込んでいない変更です。
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。
🔍 最重要システムファイルの整合性を検証中... (93 件)
🚨 ファイルの変更・改ざんが検知されました!
[内容の変更] /etc/shadow
[内容の変更] /etc/passwd
[内容の変更] /etc/group
[内容の変更] /etc/gshadow
このうち 4 件は、2026-11-12 02:32 のパッケージの更新で説明できなかったため、基準に取り込んでいない変更です。
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)
正規のOS更新等による変更の場合は 'sudo roamswitch fim update' でベースラインを更新してください。鍵を消すと、authorized_keys の行は消えました。この練習では、ファイルごと消しました。実機で正当な鍵と同じファイルにあるときは、攻撃者の行だけを消します。
残った 4 件は、最初の演習で labuser を作ったときの変更です。直後に入れた sshpass のパッケージの更新でも、説明できない変更として、基準に取り込まれませんでした。パッケージの更新が、更新と無関係な変更を基準に入れないためです。自分の変更だと確かめてから、基準を更新します。
sudo grep -c labuser /etc/passwd /etc/group /etc/shadow /etc/gshadow
sudo roamswitch fim update | tail -3
sudo roamswitch fim verify/etc/passwd:1
/etc/group:1
/etc/shadow:1
/etc/gshadow:1
✓ ベースラインDBを正常に更新・署名保存しました。 (92 件記録)
✓ SUID / SGID ファイルの基準を更新しました。 (20 件記録)
🔍 最重要システムファイルの整合性を検証中... (92 件)
✓ 改ざんは検知されませんでした。すべて正常です。 (92 ファイルを監視中)
🔍 SUID / SGID ファイルの一覧を確認中...
✓ SUID / SGID ファイルに、追加や変更はありません。 (20 件を確認)sudo roamswitch fim update は、いまの状態をそのまま基準にします。攻撃者の鍵が残ったまま実行すると、その鍵が「正しい状態」になり、fim verify に出なくなります。先に変わった箇所を調べ、自分の変更だと分かったものだけを残してから実行します。
#トンネルと、トンネルの道具
入った攻撃者は、そのサーバーを踏み台にして、奥のネットワークへ通り道を作ります。SSH だけでもできます。ssh -R は、サーバーの側に待ち受けのポートを開き、そこへの接続を攻撃者の側へ運びます。
10.99.0.3 から、トンネルだけのセッションを張ります。-N はコマンドを実行しない指定です。サーバーの 127.0.0.1:9000 への接続が、攻撃者の側の 10.99.0.3:8080 へ運ばれます。
sudo ip netns exec outside setsid sshpass -p Practice-Pass-123 ssh $F -b 10.99.0.3 -N -R 127.0.0.1:9000:10.99.0.3:8080 labuser@10.99.0.1 </dev/null >/dev/null 2>&1 &
sleep 5
sudo roamswitch ports -a | grep -A1 "Port 9000" • Port 9000 sshd PID: 2176 127.0.0.1 (ローカル限定)[注意]
↳ SSH バージョンバナー公開: SSHを最新版に更新し、必要に応じてバナーの内容を最小化してください。9000 番で、sshd が待ち受けています。-a を付けないと、127.0.0.1 だけの待ち受けは一覧に出ません。2行目の注意は、ポートの持ち主が sshd なので付いたもので、トンネルの判定ではありません。
通知の履歴も見ます。
sleep 5
sudo roamswitch notifications | sed -n 5,20p 2026-11-12T02:33:17.162653456+00:00
SSH のセッションが待ち受けを開きました: 127.0.0.1:9000(labuser)
ホスト: ubuntu (IP: 192.168.64.5)
SSH でログインしたセッション(sshd PID 2176、アカウント labuser)が、このマシンの 127.0.0.1:9000 で待ち受けています。このマシンの中からだけ接続できる待ち受けです。`ssh -R` のトンネルでは、この待ち受けへの接続が、セッションの相手の側へ運ばれます。
セッションの接続元: 10.99.0.3:52603
自分で張ったトンネルなら、許可に加えます: sudo roamswitch server allowlist add ssh-remote-listen labuser:9000 --days 30 <理由>
心当たりがなければ、セッションを切ります: sudo kill 2176
時刻: 2026-11-12 02:33:17
2026-11-12T02:33:16.316313708+00:00
🔎 不審な実行パターンを検知
ssh のトンネル(-R / -D)が開かれました (EXR-016)
プロセス: /usr/bin/ssh (PID: 2104) / 重要度: 中
詳細: ssh がリバーストンネル(-R: 相手の側に待ち受けを開き、このマシンへ運ぶ)を開きました(127.0.0.1:9000:10.99.0.3:8080)。ユーザー: root。コマンド: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1 -o LogLevel=ERROR -o ConnectTimeout=5 -b 10.99.0.3 -N -R 127.0.0.1:9000:10.99.0.3:8080 labuser@10.99.0.1
次の確認コマンド: sudo roamswitch events tree 2104
(通知のみ・遮断はしていません)上の通知が、サーバーの側で見るものです。SSH のセッション(sshd の子)が待ち受けを開いたので、ポート・アドレス・アカウント・接続元を付けて知らせました。
下の EXR-016 は、トンネルを張った側の ssh についての通知です。この練習では、攻撃者の ssh も同じ VM(名前空間)で動いているので、出ました。攻撃者のマシンから張られたときは、上の通知だけです。
どのセッションのトンネルかを調べます。
who | wc -l
loginctl list-sessions
P=$(sudo ss -ltnpH 'sport = :9000' | sed -n 's/.*pid=\([0-9]*\).*/\1/p')
ps -o pid,user,args -p $P
loginctl show-session $(cat /proc/$P/sessionid) -p Name -p RemoteHost -p Service0
SESSION UID USER SEAT TTY STATE IDLE SINCE
5 1002 labuser - - active no -
1 sessions listed.
PID USER COMMAND
2176 labuser sshd: labuser
Name=labuser
RemoteHost=10.99.0.3
Service=sshdwho は 0 行でした。端末(TTY)を持たないセッションは、who に出ません。loginctl には出ていて、接続元が 10.99.0.3 だと分かります。PID は、通知の「sshd PID」と同じです。
セッションを切ります(変更を伴う操作です)。
sudo loginctl terminate-session $(cat /proc/$P/sessionid)
sleep 2
sudo ss -ltnH 'sport = :9000' | wc -l0セッションを切ると、トンネルの待ち受けも消えました。
自分で使う -R のトンネルなら、通知の行のとおり sudo roamswitch server allowlist add ssh-remote-listen labuser:9000 --days 30 <理由> で許可します。照合するのは、セッションのアカウントとポートです。許可を足して同じトンネルを張り直すと、この通知は出ませんでした。許可は sudo roamswitch server allowlist remove ssh-remote-listen labuser:9000 で外します。
SSH の代わりに、トンネル専用の道具を持ち込むこともあります。プロセス実行の記録と攻撃手口の検知 は、chisel や ligolo-ng のような道具を、名前で数えます。スクリプトや AI エージェントの実行環境(python、node など)が、120 秒のうちに 3 種類を起動すると、EXR-010 として知らせます。
名前だけを借りた、何もしないダミーを作ります。中身は echo だけです(変更を伴う操作です)。
sudo mkdir -p /opt/labtools
for t in chisel ligolo-ng suo5; do printf '#!/bin/sh\necho "dummy %s"\n' $t | sudo tee /opt/labtools/$t >/dev/null; sudo chmod 755 /opt/labtools/$t; done
python3 -c '
import subprocess
for t in ["chisel", "ligolo-ng", "suo5"]:
subprocess.run(["/opt/labtools/" + t])
'
sleep 8
sudo roamswitch notifications | grep -m1 -B2 -A7 EXR-010dummy chisel
dummy ligolo-ng
dummy suo5
2026-11-12T02:34:11.477616267+00:00
🔎 不審な実行パターンを検知
スクリプトやエージェントが複数のペネトレーションテスト用ツールを立て続けに起動しました (EXR-010)
プロセス: /usr/bin/python3.12 (PID: 2835) / 重要度: 中
詳細: python3.12 (pid 2835) が、120 秒以内に、攻撃用ツール 3 種類を起動しました: chisel, ligolo-ng, suo5。スクリプトや AI エージェントの実行環境が、ペンテストのツールを動かしている形です
次の確認コマンド: sudo roamswitch events tree 2835
(通知のみ・遮断はしていません)
プロセス: admin / /usr/bin/dash / コマンド: /bin/sh /opt/labtools/suo5 (pid 2838)
親プロセス: python3.12 ← dash ← dash ← tart-guest-agent ← systemd重要度は「中」で、遮断はしません。最後の 2 行は、3 つ目の道具を動かしたプロセスと、その親の python3.12 です。同じ3つを、SSH でログインした人のシェルから順に動かすと、どうなるかも見ます。
sudo ip netns exec outside sshpass -p Practice-Pass-123 ssh $F -b 10.99.0.2 labuser@10.99.0.1 '/opt/labtools/chisel; /opt/labtools/ligolo-ng; /opt/labtools/suo5'
sleep 8
sudo roamswitch notifications | grep -c EXR-010dummy chisel
dummy ligolo-ng
dummy suo5
1EXR-010 は 1 件のままで、増えませんでした。人が端末から道具を動かすのは、管理や検証でよくあることなので、このルールの対象から外れます。
#入り口を閉じる
ここまでの攻撃は、パスワードのログインと、SSH のトンネルを使いました。どちらも sshd の設定で止められます。SSH と sudo の設定の診断 は、その設定の弱いところを診断します。
root の直接ログインを許し、labuser にパスワードなしの sudo を与えます(変更を伴う操作です)。戻し方は、この演習の最後にあります。
printf 'PermitRootLogin yes\n' | sudo tee /etc/ssh/sshd_config.d/00-lab.conf
echo 'labuser ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/90-lab
sudo chmod 440 /etc/sudoers.d/90-lab
sudo roamswitch status --server | grep -A2 -E "SSH rootログイン|sudo権限" [要対策] SSH rootログイン・認証設定 - ⚠️ Root直接ログインまたは平文パスワード許可中
公開鍵認証を強制し、直接のrootログインを禁止します。
↳ /etc/ssh/sshd_config で PermitRootLogin no と PasswordAuthentication no を設定してください。
--
[要対策] sudo権限・NOPASSWD監査 - ⚠️ パスワードなし全権限Sudo設定を検出
sudoers 設定で不要な NOPASSWD や過剰な特権昇格がないか検証します。
↳ NOPASSWD 設定を最小限のコマンドのみに制限してください。sshd を再起動する前から、診断に出ました。SSH の診断は、sshd が設定ファイルを評価した結果(sshd -T)を読むためです。設定が効くのは、sshd を再起動してからです。
sshd_config.d のファイルは、名前の順に読まれ、同じ項目は最初の値が使われます。00- で始めたのは、ほかのファイルより先に読ませるためです。
パスワードなしの sudo は、自分でも探せます。
sudo grep -rn NOPASSWD /etc/sudoers /etc/sudoers.d//etc/sudoers.d/90-cloud-init-users:4:admin ALL=(ALL) NOPASSWD:ALL
/etc/sudoers.d/90-cloud-init-users:7:ubuntu ALL=(ALL) NOPASSWD:ALL
/etc/sudoers.d/90-lab:1:labuser ALL=(ALL) NOPASSWD: ALL足した 90-lab のほかに、cloud-init が最初のユーザー(admin と ubuntu)に付けた行があります。
/etc/sudoers.d と /etc/ssh/sshd_config.d に置いたファイルは、その場で 重要システムファイルの改ざん監視 の通知になります。書いたプロセスも付きます。
sudo roamswitch notifications | sed -n 5,13p 2026-11-12T02:45:44.019799955+00:00
クリティカルパス改ざん検知 (FIM) (1 件の改ざん)
ホスト: ubuntu (IP: 192.168.64.5)
ハッシュが一致しない重要システムファイル:
/etc/sudoers.d/90-lab: 新しいファイル
プロセス: root / /usr/bin/tee / コマンド: tee /etc/sudoers.d/90-lab (pid 22893) ※プロセスは既に終了していたため、実行の記録(2026-11-12 02:45:43)から補いました。
SSH のログインは見つかりませんでした(systemd サービス tart-guest-agent.service のプロセスです)
推奨対応: `sudo roamswitch fim verify` で改ざん箇所を特定し復旧してください。
時刻: 2026-11-12 02:45:43この VM は tart exec で操作しているので、SSH のログインではなく、tart-guest-agent.service から書いたと出ています。00-lab.conf にも、同じ通知が出ました。
次に、入り口を閉じます。パスワードのログインを止める前に、自分の鍵を登録します。そのうえで、root のログイン、パスワードのログイン、TCP の転送(トンネル)を止めます。
sudo rm /etc/sudoers.d/90-lab
ssh-keygen -q -t ed25519 -N "" -C admin-key -f /tmp/admin_key
sudo install -m 600 -o labuser -g labuser /tmp/admin_key.pub /home/labuser/.ssh/authorized_keys
printf 'PermitRootLogin no\nPasswordAuthentication no\nKbdInteractiveAuthentication no\nAllowTcpForwarding no\n' | sudo tee /etc/ssh/sshd_config.d/00-lab.conf
sudo sshd -t && sudo systemctl restart ssh
sudo roamswitch status --server | grep "SSH rootログイン" [合格] SSH rootログイン・認証設定 - 稼働中 (公開鍵認証のみ・Root禁止)sshd -t は、設定に誤りがないかを確かめます。誤りがあると、再起動しません。
攻撃者と同じ3つの手を、もう一度試します。パスワード、鍵、鍵とトンネルです。
A="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=5 -o BatchMode=yes -i /tmp/admin_key"
sudo ip netns exec outside sshpass -p Practice-Pass-123 ssh $F -b 10.99.0.2 labuser@10.99.0.1 true
sudo ip netns exec outside ssh $A -b 10.99.0.2 labuser@10.99.0.1 'echo key ok from $SSH_CLIENT'
sudo ip netns exec outside ssh $A -o ExitOnForwardFailure=yes -b 10.99.0.2 -N -R 127.0.0.1:9000:10.99.0.2:8080 labuser@10.99.0.1labuser@10.99.0.1: Permission denied (publickey).
key ok from 10.99.0.2 35039 22
Error: remote port forwarding failed for listen port 9000正しいパスワードでも入れず、登録した鍵では入れました。トンネルは、鍵で入れても断られました。
元に戻し、練習の場も片付けます。
sudo rm /etc/ssh/sshd_config.d/00-lab.conf
sudo systemctl restart ssh
sudo rm -rf /opt/labtools /tmp/lab_key /tmp/lab_key.pub /tmp/admin_key /tmp/admin_key.pub
sudo ip netns del outside
sudo loginctl terminate-user labuser
sudo userdel -r labuser
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|allowtcpforwarding) 'permitrootlogin without-password
passwordauthentication yes
allowtcpforwarding yesこの VM の元の値に戻りました。
PasswordAuthentication no は、パスワードのログインを止めるだけです。鍵のログインは止めません。攻撃者がすでに鍵を置いていたら、設定を固めたあとも入れます。設定を固める前に、authorized_keys に見覚えのない鍵がないかを確かめます。
#見えない部分
使い捨ての Ubuntu 24.04 の VM で確かめた範囲と、コードで確かめた範囲です。
- 「総当たりのあとにログインが成功」は、成功の前に失敗があるときだけです。コードでは、しきい値の半分(既定 3 回)以上の失敗が、窓の時間のうちに要ります。最初から正しいパスワードや、盗んだ鍵で入られたときは、この通知は出ません
- 通知は、セッションを切りません。切るのは、人が
loginctl terminate-sessionで行います - 鍵の監視は、
authorized_keysとauthorized_keys2だけです。AuthorizedKeysFileで別の場所にした鍵と、AuthorizedKeysCommandで渡す鍵は見ていません(detection-coverageの表示) ssh -Rの待ち受けの通知は、知らせるだけです。トンネルもセッションも切りません。切るのは、人がloginctl terminate-sessionで行います- トンネルの道具は、名前で数えます。名前を変えた道具は数えません。コードの注記では、ngrok、frp、ssh は、毎日の作業で使われるため、名前の一覧から外しています
- SSH の診断が見るのは、
PermitRootLoginとPasswordAuthenticationです。AllowTcpForwardingは、診断の対象ではありません(コードで確認)
「SSH のセッションが待ち受けを開きました」が届きました。who には、そのセッションが出ません。どう確かめますか
解説を見る
ssh -N -Rのように端末を持たないセッションは、whoに出ません。通知の sshd の PID(ss -ltnpの待ち受けの PID と同じ)から sessionid を読むと、loginctlでアカウントと接続元が分かります。心当たりがなければ、loginctl terminate-sessionで切ります。
「総当たりのあとにログインが成功」が届き、パスワードを変えました。まだ確かめることは何ですか
解説を見る
入った直後に鍵を置かれていると、パスワードを変えても鍵で入れます。鍵のログインには失敗が要らないので、同じ通知も出ません。
fim updateを先に実行すると、置かれた鍵が基準に入ってしまいます。
#次に学ぶこと
- 総当たりの遮断と、SSH の接続元を許可リストに限る設定は、SSH の保護の設定 で扱いました。鍵を置かれても、許可リストの外からの新しい接続は入れません
- 重要なファイルの改ざんの監視の全体は、「居座りと改ざん」(準備中)で扱います
- 設定ファイルの全項目は、Linux Server の運用マニュアル にあります
対応する攻撃手法 (ATT&CK): T1572 T1098.004 T1548.003 T1059.004 T1027 T1105 T1553.001
2026-11-12に確認しました。対象は Linux 1.17.39 です。公開版 1.17.39 の入った使い捨ての Ubuntu 24.04 の VM 2 台で、fail2ban が動いたまま、ネットワーク名前空間の接続元から全演習を日本語と英語(LANG=en_US.UTF-8)で上から実行し、ssh -R の待ち受けの通知と許可リスト、コマンド行の伏せ字も確かめました。
コマンドの出力は、製品の版や環境によって変わります。違いが出たら、まず製品の版を確かめてください。