regreSSHion:OpenSSHに発見された重大な脆弱性(CVE-2024-6387)
Security Splunk Threat Research TeamほぼすべてのUnix系およびLinuxシステムにデフォルトでインストールされているOpenSSHアプリケーションに重大な脆弱性があることをQualys社が先日発見し、現在詳しい調査が行われています。
別名「regreSSHion」と名付けられたこの脆弱性CVE-2024-6387により、Linux環境で認証なしでリモートから任意のコードが実行されるリスクがあります。この脆弱性は広範囲に影響を及ぼし、世界中の多数のサーバーやインフラコンポーネントが影響を受ける可能性があります。
このブログ記事では、Splunk脅威調査チームがCVE-2024-6387の複雑な技法について解説し、影響を受けるシステムで想定されるリスクを検証して、その検出戦略と緩和策をご紹介します。
CVE-2024-6387の概要:
- 脆弱性:未認証のリモートコード実行(CVE-2024-6387)
- 影響を受けるバージョン:OpenSSH 8.5p1~9.8p1
- 対象アーキテクチャ:32bit (x86)で初期PoC済み、理論上は64bit (amd64)でも可能
- 対象システム:glibcベースのLinuxディストリビューション
- 影響:悪用されるとroot権限でのアクセスが可能
- 難易度:高(正確なタイミングが求められ複数回の試行が必要)
- 対応状況:パッチ公開済み(OpenSSH 9.8p1)
技術的な詳細
脆弱性
CVE-2024-6387はシグナルハンドラの競合状態に起因する脆弱性であり、glibcベースのLinuxシステム上のOpenSSHバージョン8.5p1~9.8p1が影響を受けます。この脆弱性は、過去の脆弱性(CVE-2006-5051)への「回帰」に起因しており、攻撃者がリモートからroot権限で任意のコードを実行することで、システムが完全に掌握される危険性があります。
シグナルハンドラの競合状態の詳細:この脆弱性はOpenSSHサーバー(sshd)でのSIGALRMシグナルの処理時に生じます。影響を受けるバージョンでは、SIGALRMハンドラによって、syslog()など、「async-signal-safe (非同期シグナルセーフ)」ではない関数を呼び出すことができます。これにより競合状態が生じ、シグナルハンドラが重要なコードセクションに割り込み可能になって、システムでの処理の整合性が損なわれる可能性があります。攻撃者は、この状態を悪用して、メモリーを操作し、任意のコードを実行します。
過去のCVE-2006-5051との関連:興味深いことに、この脆弱性は、2006年にパッチが公開された脆弱性CVE-2006-5051に回帰したものです。この過去の脆弱性もOpenSSHでのシグナルハンドラの競合状態に起因していました。この脆弱性は修正されましたが、その後、2020年10月にOpenSSH 8.5p1のログ処理基盤に変更があった際に、新たな脆弱性が誤って入り込みました。
この問題は、複雑なソフトウェアシステムのセキュリティを長期にわたって維持することの難しさを浮き彫りにしています。
悪用の具体的な条件:この脆弱性を悪用するにはいくつかの条件を満たす必要があります。
- 標的が、glibcベースのLinuxシステムで、脆弱性のあるバージョンのOpenSSH (8.5p1~9.8p1)を実行している必要があります。
- 攻撃者は、競合状態が発生しているタイミングを正確に狙って攻撃する必要があります。
- 競合状態の性質上、通常は複数回の試行が必要になります。
- Linuxシステムで効果的に攻撃を行うには、glibcでメモリーを割り当てるアロケーターの動作を利用する必要があります。
このように悪用の難易度は高いため、脆弱性としては重大レベルであるものの、攻撃を成功させるには高度なスキルと持続性が必要になります。それでも、root権限でのリモートコード実行が可能になるため、影響を受けるシステムでは深刻な問題です。
悪用の仕組み
GitHubで公開された「regreSSHion」のPoC (概念実証)エクスプロイトでは、複雑な競合状態を利用しており、攻撃を成功させるには正確なタイミングが求められ、場合によっては数千回の試行が必要になります。その仕組みを詳しく見ていきます。
タイミングと期間:エクスプロイトを成功させるチャンスがあるのは非常に短時間です。Qualys社の調査では以下のことがわかりました。
- 競合状態に当たるまでに平均で約1万回の試行が必要になります。
- 120秒間(LoginGraceTime)に100件の接続(MaxStartups)が受け入れられる場合、競合状態に当たるまでに約3~4時間かかります。
- ASLR (アドレス空間配置のランダム化)を回避する必要があることを考慮すると、エクスプロイトを完遂してrootレベルのリモートSSHアクセス権を獲得するまでに6~8時間かかる可能性があります。
システムのメモリーの状態を操作するには、特定の操作の瞬間に正確に割り込む必要があり、タイミングが非常に重要になります。
OSとアーキテクチャ:PoCの対象は主に32bit (x86)システムで、64bit (amd64)版については執筆時点で調査中です。要点は以下のとおりです。
- Debianベースのシステム、特にglibcベースのLinuxディストリビューションを中心にエクスプロイトのテストが行われました。
- 32bit版ではASLR実装の弱点が悪用され、メモリーアドレスの推測が容易でした。
- 64bit版ではASLRが強化されているため攻撃の難度は上がりますが、研究者は実行可能と考えています。
PoCで使われた主な関数:PoCエクスプロイトで使われた重要な2つの関数をご紹介します。
a) prepare_heap():
この関数の機能は、いわば、ドミノ牌を使って複雑なパターンを作ることです。コンピューターのメモリー(ヒープ)を特定の方法で配置して、エクスプロイトを機能させるために完璧な状態を作ります。具体的な操作は以下のとおりです。
- まず、10個の小さなメモリーチャンクを作成してから、ただちに解放します。これは、最終的に作るパターンの先頭に10個の小さいドミノ牌を並べるようなものです。
- 次に、大きいメモリーチャンク(約8KB)と小さいメモリーチャンク(320バイト)のペアを27組作ります。これは、大小のドミノ牌のペア27組を特定のパターンで並べるようなものです。
- これらのメモリーチャンクを特定のデータで埋めます。これは、後で並べ方がわかるようにドミノ牌にマークを付けるようなものです。
目的は、コンピューターのメモリーを予測可能な配置にして、後でエクスプロイトで利用できるようにすることです。
void prepare_heap(int sock) {
// Packet a: Allocate and free tcache chunks
for (int i = 0; i < 10; i++) {
unsigned char tcache_chunk[64];
memset(tcache_chunk, 'A', sizeof(tcache_chunk));
send_packet(sock, 5, tcache_chunk, sizeof(tcache_chunk));
}
// Packet b: Create 27 pairs of large (~8KB) and small (320B) holes
for (int i = 0; i < 27; i++) {
unsigned char large_hole[8192];
memset(large_hole, 'B', sizeof(large_hole));
send_packet(sock, 5, large_hole, sizeof(large_hole));
unsigned char small_hole[320];
memset(small_hole, 'C', sizeof(small_hole));
send_packet(sock, 5, small_hole, sizeof(small_hole));
}
// ... more heap manipulation ...
}
この関数では、エクスプロイトを実際に再現します。絶好のタイミングでドミノ牌を倒して特殊な効果を生じさせるようなものです。その仕組みは以下のとおりです。
- データパケットを作成します。これは、ドミノ倒しに最適な重さのボールを用意するようなものです。
- パケットの末尾のバイトを除くすべてをサーバーに送信します。これはボールを転がす準備をするようなものです。
- サーバーで接続がタイムアウトになる(SIGALRMが発生する)寸前(1ミリ秒前)まで待ちます。このタイミングが重要です。
- その瞬間にパケットの末尾のバイトを送信します。これは、ボールを最適な瞬間に放してドミノを倒すようなものです。
- 最後に、サーバーの応答を調べてエクスプロイトが成功したかどうかを確認します。
サーバーの正常な処理を絶好のタイミングで中断できるかどうかがこのエクスプロイトの鍵です。タイミングが合えば、攻撃者はサーバーのメモリーを操作して、高いレベル(root)の権限で任意のコードを実行できます。
int attempt_race_condition(int sock, double parsing_time, uint64_t glibc_base) {
unsigned char final_packet[MAX_PACKET_SIZE];
create_public_key_packet(final_packet, sizeof(final_packet), glibc_base);
// Send all but the last byte
if (send(sock, final_packet, sizeof(final_packet) - 1, 0) < 0) {
perror("send final packet");
return 0;
}
// Precise timing for last byte
struct timespec start, current;
clock_gettime(CLOCK_MONOTONIC, &start);
while (1) {
clock_gettime(CLOCK_MONOTONIC, ¤t);
double elapsed = (current.tv_sec - start.tv_sec)
+ (current.tv_nsec - start.tv_nsec) / 1e9;
if (elapsed >= (LOGIN_GRACE_TIME - parsing_time - 0.001)) { // 1ms before SIGALRM
if (send(sock, &final_packet[sizeof(final_packet) - 1], 1, 0) < 0) {
perror("send last byte");
return 0;
}
break;
}
}
// ... check for successful exploitation ...
}
このプロセスは非常に高い精度が求められ、成功までに何度も試行が必要になります。ジェットコースターに乗りながら針に糸を通そうとするようなもので、場合によっては攻撃を数千回試みることになるでしょう。しかし、成功すれば、攻撃者はサーバーを完全に掌握できます。
難易度が高いため現実の環境でこのエクスプロイトを成功させるのは困難です。それでも、成功した場合、攻撃者がログイン認証をせずにシステムを自由に制御できるようになるため、影響は甚大です。システム管理者は、OpenSSHを更新するとともに、このような攻撃からシステムを守るためのセキュリティ対策を講じることが重要です。
エクスプロイト対策
Splunk脅威調査チームは、侵害後の挙動に関連するアクティビティに沿った一連のLinux分析ストーリーを開発しました。これらのストーリーは、Linux環境での強力な検出機能を提供します。特に重要なストーリーが以下の4つです。
- Linux Living Off The Land:ネイティブのLinuxバイナリとユーティリティの悪用の検出に重点を置いています。
- Linux Privilege Escalation:システムでの権限昇格に使われる攻撃技法を対象としています。
- Linux Persistence Techniques:侵害されたシステムへの長期的なアクセスを維持するための技法に対処します。
- Linux Rootkit:高度なルートキットを検出するという難しい課題に対応します。
これらのストーリーには、アノマリ検出や、MITRE ATT&CKフレームワークのTTP (戦術、技法、手順)など、幅広い検出手法が取り入れられています。この分析ストーリーを導入すれば、Linuxインフラを標的とする高度な脅威について、侵害後の各段階での検出、調査、対応能力を大幅に強化できます。
OpenSSHインベントリ
UbuntuホストにインストールされているOpenSSHのバージョンが特定のエクスプロイトや攻撃に対して脆弱であるかどうかを確認するために、インベントリをサーチするSplunkクエリーを作成できます。このクエリーでは、パッケージの監査ログを分析して、本番環境のネットワーク内で見つかったすべてのOpenSSHのバージョンを特定します。
パッケージの監査ログを利用することで、OpenSSHのすべてのインスタンスを体系的に追跡および監査できます。このアプローチにより、使用しているソフトウェアバージョンを確実かつ包括的に把握できます。そこから、既知の脆弱性の影響を受けやすいバージョンをすばやく洗い出すことができます。
このインベントリ用のシンプルなサーチを次に示します。
index=unix source=package NAME= "*openssh*"
| rex field=VERSION "^1:(?<ssh_version>\d+\.\d+)"
| eval ssh_version_number = tonumber(ssh_version)
| eval vulnerable_ssh_version = if(ssh_version_number >= 8.5 AND ssh_version_number < 9.8, "Vulnerable SSH Version", "SSH Version not Vulnerable")
| stats count by NAME VENDOR ssh_version ssh_version_number VERSION vulnerable_ssh_version
パッチ未適用のバージョンを実行しているホストでsshdの「timeout before authentication」(認証前にタイムアウト)ログの記録が増えていないかどうかを確認します。この攻撃では新たなログインが何度も試行されるため、ネットワーク監視を行っている場合は、代わりに新規接続の件数が増えていないかどうかを確認することもできます。
sourcetype=journald OR sourcetype=linux:auth OR TERM(sshd) OR TERM(ssh)
TERM(Timeout) TERM(authentication) "Timeout before authentication"
| timechart count by host
緩和策
最も効果的な解決策はパッチを適用することですが、それが難しい場合は、CVE-2024-6387の脆弱性に対するリスクを軽減するための緩和策がいくつかあります。
パッチ管理
- この脆弱性が修正されているOpenSSHバージョン9.8p1以降に更新します。
- パッチをすぐに適用できない場合は、以下の緩和策を実施してリスクを軽減します。
アクセス制御
- ファイアウォールルールを使って、SSHアクセスを必要なIPアドレスとネットワークのみに制限します。
- 踏み台サーバーを設置して、アクセス制御の層を厚くします。
ホストベースの侵入防止
- fail2banなど、ホストベースのパッケージを導入して、攻撃の試行を検出およびブロックします。
- fail2banを設定して、SSHログを監視し、不審な挙動を示すIPアドレスを自動的にブロックします。
SSH設定の強化
sshd_configの以下の設定を調整して、攻撃を緩和します。
-
LoginGraceTime:
- この脆弱性を回避するには、LoginGraceTimeを「0」に設定します。
- 注意:「0」に設定すると認証試行がタイムアウトしなくなるため、システムリソースがひっ迫する可能性があります。
-
MaxStartups:
- MaxStartupsを減らして、未認証の接続数を制限します。
- 注意:この設定を低くしすぎると、攻撃が集中した場合や、ホストを利用するユーザー数が多い場合に、正規のユーザーがブロックされる可能性があります。
- 例:MaxStartups 10:30:100 (未認証の接続が10件まで受け付けられ、それを超えたら30%の割合で接続が拒否され、100件を超えたらすべて拒否されます)
-
PerSourceMaxStartups:
- この設定値を減らして、1つの送信元IPからの未認証の同時接続数を制限します。
- この設定はMaxStartupsとともに適用され、いずれか低い方の値が優先されます。
- 例:PerSourceMaxStartups 5
ネットワークのセグメント化
- ネットワークを厳密にセグメント化して、エクスプロイトが成功した場合の影響を最小限に抑えます。
- VLANやネットワークゾーンを使って、SSHアクセスが必要な重要システムを隔離します。
多要素認証(MFA):SSHアクセスにMFAを導入して、セキュリティの層を厚くします。初期のエクスプロイトを防ぐことはできませんが、攻撃者が盗んだ認証情報を悪用するのを制限できます。
監視とアラート
- SSHサービスのログ収集と監視を強化します。
- 多数のログイン試行の失敗や、不審なタイミングでの接続など、異常なSSHアクティビティについてアラートを設定します。
代替アクセス手段:重要なシステムでは、VPNソリューションなど、SSHを使用せず強力な認証を備えたセキュリティの高いリモートアクセス手段を代わりに使用することを検討します。
Snort:シグネチャベースの検出を導入します。CVE-2024-6387のエクスプロイト試行を検出するためのSnortシグネチャ(SID:63659)がCisco Talosから公開されています。セキュリティインフラにSnortを追加することで、組織の防御層を厚くできます。
これらの緩和策はいずれも、多層防御戦略の一部にすぎないことに注意してください。1つの対策を取り入れれば安心というわけではなく、複数のセキュリティ層を組み合わせることで最良の効果を発揮します。また、新しい脅威や脆弱性に対応するために、セキュリティ対策を定期的に見直して更新することも重要です。
詳しい情報
セキュリティ分析ストーリーの最新コンテンツは、GitHubからダウンロードするか、Splunk ES Content Update Appで利用できます。また、Splunk Security Essentialsでは、プッシュアップデートによってこれらの検出方法をすべて利用できます。すべてのセキュリティコンテンツの一覧は、Splunkマニュアルのリリースノートに掲載されています。
フィードバック
ご意見やご要望がございましたら、GitHubから遠慮なくお寄せください。Slackチャネル「#security-research」にご参加いただくこともできます。SlackのSplunkユーザーグループへの招待が必要な場合は、こちらの手順に従ってください。
寄稿者
この記事の執筆にあたってご協力いただいた以下の方々に感謝を申し上げます。Michael HaagとTeoderick Contreras、Splunk脅威調査チームのLou Stella、Bhavin Patel、Rod Soto、Eric McGinnis、Jose Hernandez、Patrick Bareiss、そしてSURGeのJames Hodgkinson、Jonathan Heckinger、Cisco TalosのMichael GentileとKeith Lehrschall(敬称略)
関連記事

Open Cybersecurity Schema Framework (OCSF)がついにv1.0スキーマをリリース

DECEIVEのご紹介:AIを活用した概念実証ハニーポット
