PHP2Shell徹底解説:CVE-2026-109618とCVE-2026-109619の仕組み・影響・対策
PHP2Shell徹底解説:CVE-2026-109618とCVE-2026-109619

JFrog Securityは、2026年10月21日に公表され、一般に「PHP2Shell」と呼ばれている、PHPコアの深刻度「Critical」の2件の脆弱性(CVE-2026-109618、CVE-2026-109619)を追跡調査しています。これらの脆弱性により、PHP上で動作するアプリケーションに依存せず、PHP自体において認証不要のリモートコード実行(RCE)や、Heartbleedに類似したメモリ情報の漏えいが可能になります。本記事では、脆弱性、その悪用方法、動作の仕組み、および悪用が成立するための前提条件を解説します。
10月20日、PHPセキュリティチームは、10月21日14:00(UTC)に予定しているセキュリティリリースを予告しました。このリリースでは、CVE-2026-109618とCVE-2026-109619という2件の重大な脆弱性に対処する予定であり、それぞれのCVSS v4.0スコアは9.2とされていました。

この発表のタイミングは、防御側に難しい状況をもたらしました。広く利用されているサーバーサイド技術の1つであるPHPに重大な脆弱性があることは通知されたものの、その時点では公式な技術詳細や修正版のバージョンはまだ公開されていませんでした。一方、研究者らはすでに問題の調査を進めており、悪用可能性を示す報告も現れ始めていました。
PHP2ShellのCVEの影響を受ける環境
PHPのバージョン:
- PHP 8.2.x:8.2.35より前
- PHP 8.3.x:8.3.36より前
- PHP 8.4.x:8.4.27より前
- PHP 8.5.x:8.5.12より前
設定:session.upload_progress.enabled=On(出荷時のデフォルト設定)であり、multipartアップロードを受け付けること。
サーバー環境:アプリケーションに依存しないRCEが確認されているのはApache mod_php(および、おそらくFrankenPHP)です。FPMも、正常起動後に公開される状態を介して脆弱性の影響を受けます。
対策
- PHPを
8.5.12、8.4.27、8.3.36、または8.2.35にアップグレードしてください。 - 直ちにアップグレードできない場合:PHPのセキュリティアドバイザリ(1、2)によると、管理者権限で
session.upload_progress.enabled=0(PHP 8.5.xではさらにfatal_error_backtraces=0)を設定し、変更後にすべてのワーカーを再起動し、memory_limit=-1を強制することで、部分的な緩和が可能です(RLIMIT_AS/RLIMIT_DATAは使用しないでください)。さらにpm.max_requests=1を設定すると、同一ワーカーが複数リクエストを処理するという成立条件を断つことができます。 - JFrog Xrayのユーザーは、この脆弱性の検出機能による保護を受けられます。Xrayは、スキャン対象のアーティファクトや依存関係に含まれる、影響を受ける範囲のPHPバージョンを検出します。
注意:アップロード進捗管理の設定変更は、OPcacheやバックトレースに関係する攻撃経路には影響しません。また、memory_limit=-1はリソース枯渇に対する保護を取り除きます。これらの対策は、それぞれ単独では部分的な緩和策にすぎません。
技術的な詳細
同日中にWizは、これらがCalif(セキュリティ研究ラボ)およびOpenAIとともに、Patch the Planetイニシアチブの一環として発見したCVEであることを確認しました。
JFrogチームは、脆弱性の詳細が公開される前に、その全体的な動作フローを突き止め、複数の動作するPoC(概念実証コード)を得ることができました。調査の結果、脆弱性の動作フローはおそらく次のようなものだと結論づけました。
- PHPにはmultipart POSTリクエストを処理する仕組みがあり、アップロードの進捗を追跡するためにディスク上にセッションファイルを作成します。利用者は、通常のPOSTフィールド
PHPSESSIDとして送られるセッションID、ファイル内のセッションキーの接尾部分(PHP_SESSION_UPLOAD_PROGRESS)、およびアップロードするファイル名を制御できます。ファイル名はそのまま保存されるため、攻撃者は悪意あるデータをセッションファイルに挿入できる可能性があります。 - セッションファイルは常にシリアライズ形式で保存されます。PHPエンジンはセッションを開くと、スクリプト実行前にファイル内容をデシリアライズします。デコーダーは読み込んだ内容を信頼し、そのバイト列がPHP自体によって生成されたものかを検証しません。そのため、アップロード経由でユーザーが影響を与えたデータが、実際のセッションデータとしてデコードされます。
- デシリアライズは単純な構文解析ではありません。PHPは処理中にzval(動的な値を格納するPHP内部のデータ構造)を構築し、その過程でメモリの割り当てと解放を行います。また、参照やデストラクタ処理のために、構築した値を管理用構造体に記録します。この管理処理は、すべての初期化に対応するクリーンアップが同一リクエスト内で行われることを前提としています。
- 同じワーカーが処理する別のmultipartアップロードにより、スクリプト実行前にセッションが開かれ、このファイルが再度デコードされます。最初のデコードで手順3の対応関係が破綻しています。エラーによりクリーンアップがスキップされたため、PHPのグローバル変数は解放済みの管理用メモリを指したままになります。2回目のアップロードによるメモリ割り当てがその領域を再利用し、攻撃者が制御したバイト列のデコードが実行されます。その後、セッションの書き戻し処理が偽装オブジェクトのserialize関数を呼び出し、最終的にRIPレジスタの制御に至ります。
脆弱性の内容
これらの脆弱性を利用すると、次の攻撃が可能になります。
- リモートコード実行(Remote Code Execution)
- 情報漏えい(Information Disclosure)
いずれの脆弱性も、どちらの攻撃結果を引き起こす目的にも悪用できます。
2件のアドバイザリは、同じ欠陥を異なる観点から説明しています。
CVE-2026-109618:リクエストが所有するメモリへのポインタを永続的な変数に保存してしまいます。致命的エラーが発生し、後続のリクエストが古いポインタを信頼すると、use-after-free(解放後使用)によるRCEやメモリ情報の漏えいが発生します。

CVE-2026-109619:同様のパターンが別の永続的な変数にも存在します。これには、PHP 8.5で保存される致命的エラーのバックトレースや、ワーカー間で破損した状態が引き継がれるOPcache共有メモリの状態が含まれます。

修正内容
PHPチームが提供した修正は次のとおりです。

この修正により、以下の問題に対応しています。
- メモリ不足(OOM)によって処理途中で中断しない:31c0ea7d7ff。UAFが生じていたのは、致命的なOOMによってlongjmpが実行され、ポインタをクリアする直前のコードから制御が飛んでしまうためでした。修正後は、OOMが次のVMセーフポイントでソフトエラーとして扱われる(または、より高いしきい値を超えた場合はハードな
_exit()となる)ため、クリーンアップが必ず実行され、メモリ解放前にポインタが必ずクリアされます。 - 多層防御:リクエストが別の理由で異常終了した場合でも、バックトレース、OPcache、セッション、エラー状態を含む長寿命の状態は、すべてシャットダウン時にリセットされます。これにより、古い状態が次のリクエストへ持ち越されません。
- アップロード進捗のデコード中にユーザーコードを実行しない:アップロード進捗ハンドラーによってデコードされたオブジェクトは
__PHP_IncompleteClassのまま維持され、autoloadも__destruct()も実行されません。これにより、本記事で検証したオブジェクト注入の経路も閉じられます。
偽のPoC
GitHub上に公開されているPoCを調査する中で、一部のユーザーが、この機会を利用していたずら目的の偽PoCを拡散していることがわかりました。
そのようなリポジトリの1つには、Base64でエンコードされた文字列が隠されており、一見するとマルウェアのペイロードを復号して実行するように見えます。しかし、調査の結果、実際のマルウェアではないことを確認しました。代わりに、このスクリプトは被害者の壁紙をNSFW(職場などでの閲覧に適さない)コンテンツに変更するようです。

JFrogによる支援
JFrogは両方の脆弱性を追跡し、組織が対応に備えられるよう支援しています。
JFrog XrayとCatalogにはすでにCVE-2026-109618およびCVE-2026-109619の脆弱性インテリジェンスが収録されており、各チームは既存のセキュリティワークフローを通じてこれらの問題を特定できます。


さらにJFrogのセキュリティチームは、JFrog Advanced Securityの顧客向けに、これらのCVEが実際に該当するかどうかを判断するためのコンテキスト対応スキャナーを導入しました。
IoC(侵害の痕跡)
JFrog Xray ID
| OS / プラットフォーム | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Oracle | XRAY-1141250 | XRAY-1141258 |
| Amazon | XRAY-1141248 | XRAY-1141256 |
| Suse | XRAY-1141245 | XRAY-1141253 |
| Ubuntu | XRAY-1141247 | XRAY-1141255 |
| Alpine | XRAY-1141243 | XRAY-1141251 |
| RedHat | XRAY-1141249 | XRAY-1141257 |
| Minimos | XRAY-1141246 | XRAY-1141254 |
| Debian | XRAY-1141737 | XRAY-1141738 |
| Cpp | XRAY-1141244 | XRAY-1141252 |