2026年04月19日 2m read

Cato CTRL™脅威リサーチ:MongoDBの新たな脆弱性により、リモートでサーバーを即座に停止可能に(CVE-2026-25611)

Vitaly Simonovich
Vitaly Simonovich

要旨

Cato CTRL のシニアセキュリティリサーチャーである Vitaly Simonovich は、圧縮機能が有効化されているすべての MongoDB バージョン(3.4 以降。なお 3.6 以降ではデフォルトで有効)に影響する新たな脆弱性 CVE-2026-25611(深刻度:High、CVSS スコア 7.5 / 10)を発見しました。この脆弱性は MongoDB Atlas を含む環境において悪用される可能性があり、攻撃者が MongoDB サーバーをクラッシュさせることを可能にするものです。

MongoDB Atlas のクラスターは、デフォルト設定ではインターネットから直接アクセスできる状態にはなっていません。クライアントが接続するには、プロジェクトの IP アクセスリストに登録されていること、または プライベート接続を利用していることが必要です。主なリスクは、ユーザーがアクセス設定を どこからでも接続可能(0.0.0.0/0) にしている場合に生じます。

本件は、MongoDB の バグバウンティプログラムを通じて責任ある形で報告され、同社のセキュリティチームとの連携により修正されました。

Shodan のデータによると、本稿執筆時点で 207,000 以上の MongoDB インスタンスがインターネット上に公開された状態にあります。

図1:Shodan に基づく、インターネットからアクセス可能な MongoDB サーバーの状況

MongoDB Server には、入力値の検証を行う前に、攻撃者が指定した値に基づいてメモリを確保してしまう実装上の問題があります。この欠陥により、未認証の攻撃者でも、約47KBのパケットで48MBのメモリ割り当てを強制することが可能です。その結果、わずか3〜10程度の接続で小規模な MongoDB インスタンスを数秒でクラッシュさせることができます。また、64GBクラスのエンタープライズサーバーでも、約1,350接続で停止に追い込むことが可能です。

  • 今回確認された問題:MongoDB は、OP_COMPRESSED ワイヤプロトコルメッセージに含まれる uncompressedSize フィールド(攻撃者が任意に指定可能)をもとにメモリを確保します。しかし、圧縮データが実際にそのサイズまで解凍できるかどうかの検証が行われる前にメモリ割り当てが実行されます。この挙動を悪用すると、攻撃者は 約47KBの細工されたパケットを送信するだけで、接続ごとに48MBのメモリを確保させることができます。結果として、約1027:1という非常に高い増幅率が生じます。
  • 攻撃の仕組み:問題のあるコードパスでは、message_compressor_manager.cpp 内で SharedBuffer::allocate(uncompressedSize) が呼び出され、実際の解凍処理が行われる前にメモリが確保されます。攻撃者は、実際にはごく小さなデータしか送信しない一方で、解凍後サイズを極端に大きく偽装することで、サーバーに大容量メモリの割り当てを強制します。確保されたメモリは 接続が閉じられるまで保持されるため、短時間でメモリを枯渇させることが可能になります。
  • この問題が重要である理由:
    • 事前認証なしで攻撃可能(Pre-authentication):認証情報は不要です。認証チェックが行われる前のワイヤプロトコル処理段階で悪用できます。
    • 極めて高い増幅率:約47KBの送信で 48MBのメモリ割り当てを発生させることができ、増幅率は 約1027:1 に達します。
    • 攻撃が非常に高速:サーバーは数秒でメモリ不足(OOM)に陥り停止します。例えば 512MBのインスタンスは、わずか10接続でクラッシュします。
    • デフォルト設定でも脆弱:MongoDB では 3.6以降、圧縮機能がデフォルトで有効になっています。
  • 圧縮機能が有効な MongoDB 3.4以降のバージョン(※3.6以降ではデフォルトで有効)のうち、8.2.4 / 8.0.18 / 7.0.29 より前のリリースが影響を受けます。
    • 注記:詳細については、MongoDB の公式ウェブサイトをご参照ください。

図2:MongoDB に対する DoS 攻撃のシーケンス

2025 Cato CTRL™ Threat Report | Download the report

技術概要

脆弱性の詳細に入る前に、まず今回の問題に関係する MongoDB の内部動作について簡単に説明します。

背景:関連する基本概念の理解

MongoDB ワイヤプロトコル

MongoDB ワイヤプロトコルは、クライアント(ドライバー、シェル、アプリケーション)と MongoDB サーバーの間で、TCP(Transmission Control Protocol)を介して通信するためのバイナリプロトコルです。MongoDB はデフォルトで ポート27017 を使用して接続を待ち受けます。

すべてのメッセージは、まず 16バイトの標準ヘッダーから始まり、以下の情報が含まれます。

  • messageLength: メッセージ全体のサイズ
  • requestID: リクエストを識別するユニークID
  • responseTo: このメッセージが応答するリクエストのID(リクエストの場合は0)
  • opCode: 操作の種類(例:OP_MSG は 2013、OP_COMPRESSED は 2012)

OP_COMPRESSED:ワイヤプロトコルの圧縮機能

OP_COMPRESSED(opcode 2012) は、MongoDB バージョン3.4で導入されたワイヤプロトコルの圧縮機能です。通常のメッセージを圧縮して送信できるようにするもので、標準メッセージをラップする形で処理されます。この仕組みでは、3種類の圧縮アルゴリズムがサポートされています。

compressorId アルゴリズム 備考
1 Snappy 高速で、圧縮率は中程度
2 zlib 圧縮率は高いが、処理は比較的遅い
3 zstd 速度と圧縮率のバランスに優れる(MongoDB 4.2以降で利用可能)

初期の接続処理の段階で、クライアントとサーバーは使用する圧縮方式を相互に確認し、利用する方式を決定します。いったん合意が成立すると、双方は圧縮されたメッセージを送信できるようになります。受信側は compressorId バイトを参照することで、どのアルゴリズムで解凍すべきかを判断します。

解凍処理の流れ

サーバーが OP_COMPRESSED メッセージを受信すると、MessageCompressorManager が解凍処理を担当します。処理の流れは以下の通りです。

  1. ヘッダーを解析し、uncompressedSize と compressorId を取得する
  2. uncompressedSize バイト分のバッファを確保する
  3. ペイロードをそのバッファに解凍する
  4. 解凍後のサイズが、指定されたサイズと一致しているかを検証する
  5. 内部メッセージを、非圧縮メッセージとして処理する

今回の脆弱性は、手順2が手順4より先に実行される点にあります。つまりサーバーは、サイズの妥当性を確認する前に、指定されたサイズをそのまま信頼してメモリを確保してしまうのです。

脆弱なコードパス

この脆弱性は、MongoDB のメッセージ解凍処理ロジックに存在します。サーバーが OP_COMPRESSED メッセージを受信すると、まずパケットヘッダーから uncompressedSize フィールドを取得し、その値に基づいてバッファを確保します。しかしこの時点では、圧縮データが実際にそのサイズまで解凍できるかどうかの検証が行われていません。つまり、攻撃者が解凍後サイズを過大に偽装した場合でも、サーバーはその値を信じてメモリを確保してしまいます。これが今回の脆弱性の根本原因です。

図3:MongoDB の脆弱なコード

問題点:メモリの割り当ては 158行目で、信頼できない入力値に基づいて実行されています。一方、その値の検証は 175行目で行われます。つまり、検証が行われる時点では、すでにメモリ確保が実行された後になっています。

ワイヤプロトコルの構造

OP_COMPRESSED メッセージは、次の構造になっています。

Wire Header(16バイト) messageLength、requestId、responseTo、opCode=2012
originalOpcode 4バイト(通常は OP_MSG の 2013)
uncompressedSize 4バイト ← 攻撃者が任意に指定可能
compressorId 1バイト(1=snappy、2=zlib、3=zstd)
compressedMessage 可変長(実際の圧縮データ)

uncompressedSize フィールドは 4バイトで構成されており、理論上は 約4GBまでのサイズを指定することが可能ですMongoDB では、1メッセージあたり 48MB に上限が設けられていますが、それでも 複数の接続を通じて繰り返し要求されると、サーバーに大きな負荷を与えるには十分な量になります。

図4: パケット構造の比較:正規トラフィックと悪意あるトラフィック

攻撃の仕組み

  1. 攻撃者は、zlib で圧縮した約47KBのペイロードを作成します(内容は正当な繰り返しデータ)。
  2. 攻撃者はまた、uncompressedSize フィールドに、許容される最大値(48,000,000バイト)を設定します
  3. サーバーはパケットを受信し、ヘッダーから uncompressedSize を読み取ります
  4. サーバーは解凍処理を行う前に、48MBのバッファを確保します。
  5. データは正常に解凍されるため処理自体は問題なく完了しますが、 確保されたメモリはそのまま保持されます。
  6. 攻撃者は同時接続数を増やしていきます(例:512MBサーバーでは約10接続、1GBでは約25接続、など)。
  7. その結果、サーバーは利用可能なメモリを使い切り、カーネルによって OOM(Out Of Memory)として強制終了されます(終了コード137)。

ここで重要なのは、送信される圧縮データ自体は正当であるという点です。実際に指定されたサイズまで解凍可能なため、サーバーは接続を維持したまま次のメッセージを待ち続けます。その結果、確保されたメモリも解放されずに残り続けます。実際の検証では、512MBの MongoDB インスタンスは、わずか10接続(約457KBの攻撃トラフィック)でクラッシュしました。また、8GBのインスタンスでも198接続(約9MB)で停止することが確認されています。

OOM を引き起こすために必要な接続数

MongoDB バージョン8.0を Docker コンテナ上で動作させ、メモリ制限を変えながら、OOM(メモリ不足)による停止が発生するまでに必要な接続数を検証しました。各接続は 約47KBのペイロードを送信しますが、サーバーには 48MBのメモリ割り当てが発生します。つまり、約1,027倍という極めて高い増幅率になります。たとえて言えば、短いメール1通分(47KB)のデータを送るだけで、サーバーにポッドキャスト1本分(48MB)のメモリ確保を強いるようなものです。この処理が接続ごとに繰り返されることで、短時間のうちにメモリが枯渇します。

サーバーメモリ 必要接続数 送信データ量 強制メモリ確保量 クラッシュまでの時間
256 MB 3 137 KB 144 MB 1秒未満
512 MB 10 457 KB 480 MB 約2秒
1 GB 25 1.1 MB 1.2 GB 約3秒
2 GB 45 2.1 MB 2.2 GB 約4秒
4 GB 85 3.9 MB 4.1 GB 約5秒
8 GB 198 9.0 MB 9.5 GB 約8秒

主なポイント:

  • 計算式:最小接続数 ≈ (RAM_MB – 100) / 48 MongoDB はベース動作だけで 約100MBのメモリを使用するため、それ以外のメモリが攻撃の対象になります。
  • ほぼ比例して増加: 必要な接続数は サーバーのメモリ容量にほぼ比例して増加します(目安として 1GBあたり約20接続)。
  • ごく少ない通信量で成立: 8GBのサーバーでも、約9MBの攻撃トラフィックで停止させることが可能です。
  • 単一マシンから実行可能: これらのテストは すべて単一の攻撃用マシンから実施されています。

実運用環境への当てはめ:

デプロイメント 一般的なメモリ容量 推定必要接続数 推定送信データ量
Atlas M0 (Free) 512 MB ~10 ~457 KB
Atlas M10 2 GB ~45 ~2.1 MB
Atlas M30 8 GB ~198 ~9.0 MB
Atlas M60 32 GB ~680 ~31 MB
エンタープライズ 64 GB ~1363 ~64 MB

この結果から分かるように、十分なリソースを備えたエンタープライズ環境であっても影響を受ける可能性があります。例えば、一般的な家庭用インターネット回線からでも、64GBの MongoDB サーバーを1分未満で停止させることが可能です。

図5: MongoDB サーバーを停止させるために必要な接続数

結論

今回明らかになった MongoDB の脆弱性は、攻撃者が MongoDB サーバーを停止に追い込むことを可能にするものです。Shodan のデータによると、本稿執筆時点で 207,000以上の MongoDB インスタンスがインターネット上に公開されています。本来、MongoDB の圧縮機能はパフォーマンス向上を目的として導入されたものですが、この脆弱性により 攻撃の入口となる可能性があることが分かりました

対策自体は比較的シンプルです。メモリを割り当てる前に、uncompressedSize の値が 実際の圧縮データの長さと整合しているかを検証すべきです。圧縮アルゴリズムには理論上の圧縮率の上限があり、例えば zlib がランダムデータを 1027:1 の比率で圧縮することは現実的ではありません。接続ごとにメモリ割り当てが積み重なることで、最終的には MongoDB サーバーがクラッシュします。そのため各組織は、自社の MongoDB 環境をインターネットに直接公開する必要が本当にあるのかを改めて確認することが重要です。

防御策

MongoDB 利用者向け:

  • ネットワークアクセスの制限: ファイアウォールや VPN を利用し、MongoDB へのアクセスを信頼できるネットワークに限定してください。
  • 接続数の制限: maxIncomingConnections を設定するとともに、OS レベルでも接続レート制限を実装することが推奨されます。
  • メモリ使用量の監視: メモリ使用量の異常な増加を検知できるよう、監視とアラートを設定してください。
  • 圧縮機能の無効化の検討: 圧縮によるメリットが小さい環境では、–networkMessageCompressors=disabled を設定し、圧縮機能を無効化することも検討できます。
  • 圧縮機能が有効な MongoDB 3.4以降(※3.6以降ではデフォルトで有効)のうち、8.2.4 / 8.0.18 / 7.0.29 より前のバージョンが影響を受けます。該当する場合は、修正済みのバージョンへ更新してください。

Cato 利用者向け:

  • IPS 保護: Cato の IPS は、MongoDB を狙う 不正な OP_COMPRESSED パケットや、異常な接続パターンを検知しブロックします。
  • ネットワーク分離:Cato SASE プラットフォームのネットワークセグメンテーション機能を活用し、データベース通信を信頼できないネットワークから分離します。
  • MDR による監視 Cato MDR は、接続フラッドや異常なパケットサイズなど、MongoDB を標的とした不審な通信パターンを分析・対応します。

侵害の指標(IoC)

ネットワーク上の兆候:

  • 単一の送信元から ポート27017(または設定された MongoDB ポート)への大量の TCP 接続
  • OP_COMPRESSED パケット(opCode 2012)で、uncompressedSize が大きく(10MB以上)、しかし パケット全体のサイズは小さい(100KB未満)
  • 接続が短時間で大量に確立され、その後 アイドル状態の接続が維持される

システム上の兆候:

  • MongoDB プロセスのメモリ使用量が急激に増加
  • システムログに OOM Killer による mongod プロセスの終了イベント
  • MongoDB の終了コード 137(OOM による SIGKILL)

Related Topics

Vitaly Simonovich

Vitaly Simonovich

Senior Security Researcher

イスラエルを拠点とするヴィタリーは、アプリケーションとデータセキュリティを中心に、サイバーセキュリティ分野で8年以上の経験があります。過去には、IncapsulaとImpervaでセキュリティアナリストと研究者のチームを率いていました。仕事とは別に、サイバーセキュリティコミュニティに積極的に貢献しているヴィタリーは、定期的に研究ブログやウェビナーを公開し、さまざまなセキュリティカンファレンスでも講演を行っています。また、サイバーセキュリティの教育にも熱心で、地元の大学で教鞭をとっています。余暇にはキャプチャー・ザ・フラッグ(CTF)の課題を解くのが好きで、楽しみながら自らのスキル向上に役立てています。

Read More