境界の崩壊とSSHという「牙城」:ポート22を悪用するトンネリングをどう視認するか
ネットワークエンジニアの端くれなら一度は経験があるはずだ。夜中の3時、なぜか外部の怪しいIPから、自社の管理サーバーの 22/tcp に対して、執拗なブルートフォースの残骸がログを埋め尽くしている光景を。
多くの現場では、SSHは「信頼された管理者の道具」という前提で聖域化されている。だが、ゼロトラストの文脈で語るならば、SSHは最も強力な「検問所なきバイパス」になり得る。特に、一度侵害された管理端末が、SSHのポートフォワーディング(LocalForward や DynamicForward)を駆使して、本来到達できないはずの内部ネットワークへと触手を伸ばすシナリオは、インフラアーキテクトにとって悪夢以外の何物でもない。
今日は、この「SSHトンネリング」という見えざる脅威を、パケットレベルの挙動から解剖し、どう制御・可視化すべきか、その深淵に迫ろう。
—
SSHハンドシェイクの「闇」を可視化する
SSHのセッション確立プロセスは、暗号化される前に SSH-2.0-OpenSSH_x.x といったバージョン文字列を交換する。この Banner Exchange 自体は平文で行われるため、IDS/IPSによる署名ベースの検知は容易だ。しかし、問題はその後だ。
KEXINIT(鍵交換)が完了し、NEWKEYS が送信された瞬間、通信路は完全に暗号化されたブラックボックスと化す。ここでインフラがなすべきことは、ペイロードの中身を覗くことではなく、「パケットの挙動」というメタデータから意図を読み解くことだ。
不正なトンネリングを見抜く統計的アプローチ
SSHトンネルが確立されると、通常の対話型セッションとは明らかに異なる挙動を示す。
1. パケット長分布の偏り: 対話型シェルは、人間が入力するたびに小さなパケットが断続的に発生する。一方、トンネリングによるファイル転送や踏み台通信は、MTU ギリギリのパケットが連続して流れる。
2. TCPフローの持続時間: 管理用セッションは「放置」されることが多いが、トンネリングはデータ転送を目的とするため、フローのバイト単価(Byte per Flow)が圧倒的に高い。
これらを監視するために、eBPF を用いてカーネルレベルでパケットサイズとセッションの相関をフックするのが現代の最適解だ。
—
パフォーマンスとセキュリティの二律背反を調停する
SSHのパフォーマンスチューニングは、往々にしてセキュリティ設定と衝突する。特に TCP window scaling や TCP BBR を適用すると、トンネル経由のデータ流出速度が劇的に向上してしまうからだ。
SSHのパケット圧縮とRTT削減の罠
SSHの Compression yes 設定は、過去には有効だったが、現在は CRIME や BREACH といったサイドチャネル攻撃の温床になり得る。また、ネットワーク層でパケット圧縮を行うと、トラフィック分析のシグネチャが崩れ、IDSによる検知を困難にする。
もし、貴殿のインフラでSSHのパフォーマンスを限界まで引き出しつつ、セキュリティを担保したいのであれば、以下のパラメーターを sshd_config に適用し、暗号スイートをモダンなものに絞るべきだ。
# 暗号スイートをモダンなものに限定(脆弱なCBCモードやHMAC-MD5を排除)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# 信頼できない送信元からのポート転送を物理的に禁じる
AllowTcpForwarding no
X11Forwarding no
# 接続維持の最適化(セッションハイジャックのリスクを低減)
ClientAliveInterval 300
ClientAliveCountMax 0
—
現場で即効性のある監視コード:コネクション・アナライザー
Pythonの scapy を使い、特定のホストから発生しているSSHセッションの「不自然なパケット量」を監視する簡易的なスクリプトを書いてみた。これを監視サーバーで動かし、一定の閾値を超えた Source IP を自動的に iptables で遮断するフローに繋げる。
from scapy.all import sniff, IP, TCP
# SSHポート(22)のトラフィックを監視
def analyze_ssh_traffic(packet):
if packet.haslayer(TCP) and packet[TCP].dport == 22:
# パケットサイズが極端に大きいフローを検出(トンネリングの予兆)
if len(packet) > 1400:
print(f"[!] 警告: SSHセッションにて巨大パケットを検出: {packet[IP].src}")
# ネットワークインターフェースを監視
sniff(filter="tcp port 22", prn=analyze_ssh_traffic, store=0)
—
結論:境界なき時代の「SSHガバナンス」
SSHはもはや、無条件に信頼できる管理用プロトコルではない。クラウドネイティブな環境においては、SSH Bastion(踏み台)を廃止し、Identity-Aware Proxy (IAP) や、Tailscale に代表される WireGuard ベースのオーバーレイネットワークへ移行することが、最も現実的かつ強固な防御策となる。
しかし、レガシーなインフラを抱える我々にとって、今すぐ全てを置き換えるのは不可能だ。だからこそ、SSHの挙動をパケットレベルで監視し、sshd_config を厳格に管理し、TCP スタックの挙動を理解する。
泥臭いかもしれないが、この「足元の積み重ね」こそが、サイバー攻撃という海に沈まないための唯一の防波堤なのだ。貴殿のネットワークが、今日も静穏であることを願っている。
コメント