SSHは「開かれた門」か「忍び寄る影」か?—ポート22を悪用したデータ持ち出しを封じ込める技術
ネットワークエンジニアとして現場を渡り歩いていると、「SSHは暗号化されているから安全だ」という甘い言葉を耳にすることがあります。しかし、残念ながらそれは大きな誤解です。
SSH(TCP 22番ポート)は、管理者にとっての命綱であると同時に、攻撃者にとっては「境界防御を無力化するための最も都合の良いトンネル」になり得ます。今日のテーマは、侵害された端末から外部へデータを持ち出す、あるいは多段踏み台として機能する「SSHポートフォワーディング」の検知と防御についてです。
教科書通りの「ポートを閉じる」という対策だけでは、現代の柔軟な開発現場は回せません。どうやって「正当な通信」と「悪意あるトンネル」を見分けるか。その泥臭い現場の知見を共有しましょう。
—
1. なぜSSHが「トンネリング」に悪用されるのか
攻撃者は、ネットワーク境界のファイアウォール(FW)を回避するためにSSHの Local Port Forwarding や Dynamic Port Forwarding を利用します。
例えば、管理端末がマルウェアに感染したとしましょう。攻撃者はその端末から外部のC2サーバーに向けてSSH接続を確立します。このとき、内部ネットワークのサーバーに対して行われる通信は、すべて ssh セッションという「暗号化された箱」の中にカプセル化されます。FWから見れば、それはただの「22番ポートの暗号化された通信」であり、中身で何が行われているのか(MySQLのクエリなのか、機密データの転送なのか)は判別できません。
通信フローの罠
SSHの通信は RFC 4253 で規定されるSSH-TRANS層を経て確立されますが、ポートフォワーディングが発生すると、以下のような不自然な挙動が観測されます。
1. 初期接続: 特定の外部IPに対する長時間のセッション確立。
2. 多重化: 一つのセッションの中で、本来の管理者行動とは異なる複数の channel がオープンされる。
3. ペイロードの偏り: 業務時間外や、通常では通信が発生しないサーバーへの TCP トラフィックの急増。
—
2. 現場で使える「怪しいトンネル」の検知術
IDS/IPSがシグネチャベースで検知できない場合、私たちは「通信の統計情報」に頼る必要があります。特に監視すべきは「接続時間」と「データ転送量」の相関です。
NetFlow/IPFIXによる異常検知
パケットの中身が見られない場合、フロー情報から「SSHセッションの継続時間」と「パケット数/バイト数」を分析します。
- 検知ロジック例:
duration > 3600s(1時間以上接続しっぱなし)total_bytes_out > threshold(特定の閾値を超えたアップロード)packet_size_variance(SSHの管理操作にしては不自然に大きなパケットが続く)
—
3. 実践的防御:設定とコードで縛る
防御の基本は「誰が、どこへ、何のために」を縛ることです。SSHの sshd_config を適切に設定し、クライアント側でも制御をかけます。
sshd_configによる制限
もし、そのサーバーがポートフォワーディングを必要としないなら、即座に無効化すべきです。
# /etc/ssh/sshd_config
# ポートフォワーディングを全面的に禁止する(これが最も強力)
AllowTcpForwarding no
# もし特定のユーザーのみに許可する場合
Match User secure_user
AllowTcpForwarding yes
Pythonによる「不審なポート利用」の監視例
ネットワーク上の Socket 状況を監視し、期待しないプロセスが 22 番ポートを介した通信を行っていないかチェックするスクリプトの概念です。
import psutil
# 実行中のプロセスからSSHに関連する不審な接続を監視
def monitor_ssh_connections():
for conn in psutil.net_connections(kind='tcp'):
# リモートポートが22番、かつ自分のプロセスが管理対象外のもの
if conn.raddr and conn.raddr.port == 22:
print(f"警告: 不審なSSH接続を検知: {conn.laddr} -> {conn.raddr}")
# ここでさらにプロセス名を確認し、許可リストになければkillする等の処理を実装
if __name__ == "__main__":
monitor_ssh_connections()
—
4. Web API設計における「出口」の意識
Web APIを設計する際、サーバーから外部のAPIを叩くシーンがあるかと思います。その際、安易に curl や requests を利用するのではなく、「出口(Egress)の制御」をアーキテクチャに組み込んでください。
例えば、コンテナ環境から外部への通信を許可する場合、直接インターネットに出すのではなく、必ずフォワードプロキシを経由させ、プロキシ側で CONNECT メソッドの宛先をホワイトリストで制御します。
curlで試すトンネル接続の確認
攻撃者が端末から踏み台として利用しているか、以下のコマンドでプロキシ経由の疎通をテストできます。
# プロキシ経由で外部のAPIを叩く(意図しない先へ繋がらないか確認)
curl -x http://proxy.internal:8080 -v https://api.example.com/data
—
最後に:ネットワークは「嘘をつかない」
SSHのトンネリングを完璧に防ぐ唯一の方法は、「SSHの利用を制限し、かつ通信を可視化(復号・検査)すること」です。
しかし、現場のエンジニアにとって最も重要なのは「いつもと違う」という直感です。ネットワークフローの異常なスパイク、深夜の不自然な接続、管理端末からの奇妙な通信。これらはすべて、システムが発している「助けて」の信号です。
マニュアルを鵜呑みにせず、自分の管理するネットワークの「正常な波形」を理解してください。それができれば、どんなに巧妙な攻撃者も、その不自然なパケットの軌跡を隠し通すことはできません。
さあ、今すぐログを確認し、あなたの境界防御に「風穴」が開いていないかチェックしましょう。現場からは以上です。
コメント