ゼロデイ攻撃の本質とは? PHPの重大脆弱性から考える「メモリ管理の破綻」
2026年10月21日、PHPに存在する2件の重大な脆弱性が修正・公開されました。
「PHP2Shell」と呼ばれる今回の問題は、認証されていない外部の攻撃者が、条件次第でサーバー上のプログラムを不正に実行できてしまうというものです。
深刻度はCVSS v4.0で9.2。
ただ、今回のニュースを見て、一つ疑問を感じました。
「これって、昔から指摘されていた問題ではないのか?」
さらに調べていくと、メモリ不足、初期化処理、プログラム内部の状態管理という、非常に興味深い問題が見えてきました。
今回は、ゼロデイ攻撃の定義から始めて、PHPの脆弱性が発生する仕組み、そしてJavaScriptやHTMLとの関係まで整理してみたいと思います。
⸻
1. そもそもゼロデイ攻撃とは何か?
ゼロデイ攻撃(Zero-Day Attack)とは、ソフトウェアの脆弱性に対する修正プログラムが提供される前に、その脆弱性を悪用する攻撃です。
重要なのは、「脆弱性が存在すること」と「ゼロデイ攻撃が行われること」は同じではないという点です。
例えば、あるソフトウェアに欠陥が10年間存在していたとします。
その欠陥が攻撃者に発見され、修正される前に悪用された場合、ゼロデイ攻撃となります。
一方、修正プログラムが公開された後に、アップデートされていないシステムを狙う行為は、通常、既知の脆弱性を悪用するN-Day攻撃として区別されます。
つまり、ゼロデイかどうかは、欠陥が生まれてからの経過年数だけで決まるものではありません。
攻撃が行われた時点で、修正が提供されていたかどうかが重要なのです。
2. PHPの脆弱性は、以前から問題になっていた
PHPは、WebサイトやWebアプリケーションのサーバー側で広く利用されているプログラミング言語です。
今回のPHP2Shellでは、主に次の2件の脆弱性が問題となりました。
CVE-2026-109618:メモリ不足による内部状態の破綻
PHPがメモリ不足に陥ると、処理を途中で中断することがあります。
その際に、初期化が完了していない内部データが残り、終了処理がそれを正常なデータとして扱ってしまう場合があります。
CVE-2026-109619:解放済みメモリへの参照が残る問題
あるリクエストで使用したメモリが解放された後も、そのメモリを指す情報がPHPの内部に残ってしまうことがあります。
次のリクエストが、その無効な情報を利用してしまう問題です。
そして、この種の問題には長い歴史があります。
2004年には、PHPのメモリ制限処理に関係する遠隔攻撃の問題が報告されています。
2019年には、フォームデータの処理中にメモリ不足が生じ、一時ファイルが適切に削除されない問題が報告され、2020年に修正されました。
2024年のセキュリティ監査でも、関連するメモリ不足時の問題が指摘されています。
そして2026年、研究者によって新たな攻撃経路から遠隔コード実行が可能であることが実証されました。
ただし、過去に報告された脆弱性と今回の2件のCVEが、すべて同一というわけではありません。
ここから分かるのは、既知の問題を修正しても、関連する設計上の危険性が別の場所に残ることがあるということです。
3. メモリに負荷をかけると、なぜ攻撃できるのか?
最初は、単純に大量のメモリを消費させてサーバーを停止させる攻撃なのかと思いました。
しかし、実際には違います。
通常、プログラムはメモリを使用するとき、必要な領域を確保し、初期化してから利用します。
処理が終了したら、不要なメモリを解放します。
メモリの確保に失敗したとしても、プログラムが安全に終了できれば、それ自体は問題ありません。
では、何が危険なのでしょうか。
それは、処理の途中で異常が発生した結果、内部の状態が不完全なまま残ることです。
例えば、プログラムが次の順序で処理するとします。
① メモリを確保する
② データの初期化を開始する
③ 初期化を完了する
④ データを使用する
⑤ メモリを解放する
正常な状態であれば問題ありません。
しかし、②の途中でメモリ不足が発生し、初期化が中断されたらどうでしょうか。
本来であれば、そのデータは不完全なものとして適切に処理されなければなりません。
ところが、プログラムが初期化済みだと誤って判断すると、不正なメモリアクセスにつながる可能性があります。
つまり、メモリ不足自体が不正アクセスを発生させるのではありません。
メモリ不足をきっかけに、安全であるはずの内部状態が崩れてしまうことが問題なのです。
4. 「内部状態が壊れる」とは何を意味するのか?
ここが今回、特に興味深いと感じた部分です。
そもそも「内部の状態が壊れる」とは、技術的にどのような状態なのでしょうか。
整理すると、次のように定義できます。
内部状態の破綻とは、プログラムが正常に動作するために維持しなければならない、内部データの整合性や不変条件が失われた状態です。
不変条件(Invariant)とは、プログラムの処理中に守られるべき条件を意味します。
例えば、メモリ管理では次のような条件が必要になります。
* データは必要な初期化が完了してから使用する。
* 解放されたメモリを再び使用しない。
* メモリへの参照先が有効であることを保証する。
* メモリを所有する主体と解放する責任を正しく管理する。
* 処理が途中で失敗しても、安全な状態に戻せるようにする。
これらの条件が失われたまま処理を継続すると、プログラムは本来想定していない状態へ移行する可能性があります。
今回のPHPの問題も、こうした不変条件の破綻として理解できます。
ただし、ここで注意したい点があります。
内部状態が不整合になったからといって、必ず攻撃が成功するわけではありません。
内部状態の不整合、不正なメモリアクセス、攻撃者による制御の獲得は、それぞれ区別すべき段階です。
不整合が発生しても安全に停止できる場合がありますし、不正なメモリアクセスが起こっても、攻撃者が任意のコードを実行できるとは限りません。
この違いを理解することが、脆弱性の危険性を正確に評価するうえで重要になります。
5. 初期化するときに、外部から侵入する隙間ができるのか?
ここで、もう一つ疑問が生まれました。
「初期化処理の途中で、外部から侵入できる隙間が発生しているのではないか?」
結論としては、少し違います。
PHPは、Webサーバーを通じて外部から届いたHTTPリクエストを処理します。
つまり、外部からの入力を受け付ける仕組みそのものは、最初から存在しています。
問題は、その入力を処理する途中でPHPの内部状態が破綻してしまうことです。
今回の脆弱性は、Webアプリケーションのログイン処理に問題があるという話ではありません。
PHPの実行エンジン自身が、外部から届いた入力を処理する際に、メモリ管理の不変条件を維持できない場合があるという問題です。
そのため、アプリケーション側のPHPコードに明確な欠陥がなくても、影響を受ける可能性があります。
外部から侵入するための新しい入口が開くというより、既存の入力経路を通じて内部処理の安全性が崩される、と考える方が正確です。
6. JavaScriptやHTMLでも同じことは起こるのか?
ここまで考えると、PHP以外でも同じような問題が発生するのではないか、という疑問が生まれます。
例えば、JavaScriptやHTMLです。
結論から言えば、どちらでも関連する問題は起こり得ます。
ただし、仕組みには違いがあります。
JavaScriptの場合
JavaScriptでは、一般的なプログラムがメモリを直接解放するわけではありません。
通常は、JavaScriptエンジンがメモリ管理を担当しています。
例えば、Google Chromeで利用されているV8というJavaScriptエンジンです。
V8は主にC++で実装されています。
そのため、JavaScriptのコードそのものが正常でも、それを処理するV8の内部実装に欠陥が存在すれば、メモリ管理が破綻する可能性があります。
つまり、JavaScriptを使って引き起こされた脆弱性であっても、根本原因がJavaScriptエンジンのC++実装に存在する場合があるのです。
HTMLの場合
HTMLは、厳密にはプログラミング言語ではなく、文書の構造を定義するマークアップ言語です。
HTMLそのものがメモリの確保や解放を指示するわけではありません。
しかし、ブラウザはHTMLを解析し、画面を構築するために内部でメモリを利用します。
もしHTMLの解析処理に欠陥が存在すれば、特定のHTMLデータを読み込ませることで、ブラウザ内部の不正なメモリ操作が引き起こされる可能性があります。
ここで重要なのは、脆弱性を引き起こす入力に使われる言語と、脆弱性が存在するソフトウェアの実装言語は必ずしも一致しないという点です。
7. この問題を防ぐには何が必要なのか?
今回のPHP2Shellについて、PHP公式は修正版への更新を強く推奨しています。
2026年10月21日に公開された修正済みバージョンは、PHP 8.5.12、8.4.27、8.3.36、8.2.35です。
PHP 8.1以前のバージョンでは、公式プロジェクトによる通常の更新サポートが終了しているため、サポート対象バージョンへの移行、または利用しているディストリビューションや保守ベンダーが提供する修正を確認する必要があります。
Webアプリケーション自体を更新しても、PHPの実行エンジンの欠陥が解消されるとは限りません。
また、一般的なソフトウェア設計の観点から考えると、正常時の処理だけでなく、異常時にも不変条件を維持することが重要です。
特に、メモリ不足、初期化の中断、例外処理、後片付け、リクエスト間での状態の引き継ぎといった場面では、異常な状態が次の処理へ持ち越されない設計が求められます。
8. 最後に:脆弱性の本質は「内部状態の整合性」にある
今回のPHP2Shellを調べる中で、最も印象に残ったのは、メモリ不足そのものではありませんでした。
本当に重要なのは、想定外の出来事が起きたときにも、プログラムが内部状態の整合性を維持できるかどうかです。
正常な入力が与えられ、正常な処理順序で実行されるのであれば、プログラムは問題なく動くかもしれません。
しかし、外部から意図しない入力が与えられたり、処理が途中で中断されたりした場合はどうでしょうか。
そのとき、本来維持されるべき条件が崩れ、内部データが不正な状態のまま利用されれば、そこから脆弱性が生まれる可能性があります。
そして、この考え方はPHPに限った話ではありません。
JavaScriptエンジン、ブラウザ、OS、データベースなど、さまざまなソフトウェアに共通するものです。
もちろん、内部状態の不整合がすべてメモリ破壊や遠隔コード実行につながるわけではありません。
それでも、**「どの言語が危険なのか」ではなく、「どの処理段階で、何の不変条件が失われるのか」**という視点で考えることは、セキュリティを理解するうえで非常に重要だと感じました。
ゼロデイ攻撃の本質を理解するには、単に未知の脆弱性を探すだけでは不十分なのかもしれません。
想定外の状態に陥ったとき、システムがどのような振る舞いをするのか。
そこにこそ、脆弱性の根本的な問題が隠れているのだと思います。
⸻
参考資料
* PHP公式:2026年10月のセキュリティアドバイザリ
* Calif Research:PHP2Shellの技術解説と発見の経緯
* PHP公式バグ記録:Bug #78876
* OSTIF:PHPセキュリティ監査
※本記事は2026年10月22日時点の公開情報に基づいています。攻撃の成立条件はPHPのバージョンや実行環境によって異なります。