技術約6分で読めます

php2shell修正後のPHP 8.5.12に残ると主張された脆弱性を整理した

いけさん目次

TL;DR

確定 2026年10月21日、PHPが8.5.12・8.4.27・8.3.36・8.2.35で未認証RCE2件(CVE-2026-109618/109619、通称php2shell、CVSS 9.2)を修正した。公開当日から実地の攻撃観測が出ている
主張 パッチ後の8.5.12にも抜けが残るという個人の自己公開ページが同日に出た。PHPへの正式な届出はされておらず、RCEだとする2項目は第三者が追試できる形になっていない
対応 まず修正版へ更新する。「残る」という主張の確度はまだ低いので、更新を止める理由にはしない


2026年10月21日、PHPがアドバイザリを公開し、8.5.12・8.4.27・8.3.36・8.2.35で未認証のリモートコード実行(RCE。攻撃者が外部から任意のコードをサーバー上で動かせる状態)2件を修正した。
CVE番号はCVE-2026-109618とCVE-2026-109619、どちらもCVSS v4.0(脆弱性の深刻度を0〜10で表す指標)で9.2と高い。通称は「php2shell」だ。watchTowrは自社のハニーポット(攻撃を観測するためのおとりサーバー)で公開当日に悪用を試みる通信を確認したとしている(watchTowr FAQ、Help Net Security)。

この修正の直後に、「パッチ後の8.5.12にもまだ抜けが残っている」と主張する個人の自己公開ページ(php2shell-zeros)が出た。
ページにはRCEの実証コードや攻撃スクリプトも同梱されている。再現には触れず、どの主張が確定していてどこがまだ裏取り前かだけを確かめる。

公式が修正した2件

アドバイザリは公式の GHSA-w8hw-w9fx-j79w と GHSA-6wmf-4rv5-p3rp で、どちらも10月21日公開。公式チェンジログでは8.5.12のリリース日付が10月22日になっているので、告知・アドバイザリ公開は21日、チェンジログ上の版の日付は22日と分かれている(PHP公式チェンジログ)。

2件は原因が別だが、どちらも未認証でRCEに至りうる。深刻度はともにCVSS 9.2だ。

CVE概要
CVE-2026-109618PHPはメモリ不足時に longjmp() で処理を中断する。初期化が終わる前のメモリに到達した状態で確保が失敗すると、無効なままのリクエストメモリが残り、終了処理がそれを有効なものとして扱う
CVE-2026-109619終了したリクエストのメモリを指したまま残ったワーカー(リクエストを処理する常駐プロセス)内のグローバル状態を、次の処理が通常の初期化より前に使ってしまう解放後使用(UAF)。成立には「書き込む側」と「使う側」の両方が要る

longjmp() はC言語で、関数の呼び出し階層を飛び越えて以前の地点へ処理を戻す仕組みを指す。CVE-2026-109619にはきっかけが2つある。公式はPHP 8.5の fatal_error_backtraces(致命的エラー時にバックトレースを保存する機能)を通る形を最も強く実証された例としている。もう一方がセッションのアップロード進捗(アップロード中の進み具合を記録する機能)を通る形で、こちらは既定で有効だ。

修正された系列と、更新が限られる古い系列は分かれる。

系列状況
8.5 / 8.4 / 8.3 / 8.28.5.12・8.4.27・8.3.36・8.2.35で修正済み
7.4 / 8.0 / 8.1限定的な更新のみ
5 系公式の修正なし

watchTowrは影響範囲を「PHP 5・7・8の全体」と報告しているが、この広い範囲はベンダーのアドバイザリでは確認されていない、と同社自身が注記している。デフォルト構成で成立するかも、一次情報でははっきりしない。自分の環境が該当するかは、使っているPHPのバージョンと、ホスティング側がパッチを当てたかで判断する。

「まだ抜けがある」という同日の主張

公開当日は、この修正をめぐって「パッチが不完全だ」という言説がSNSで広がった。一次情報を調べたら、多くは別の古いバグ由来か、追試の途中で未確定だった。冒頭の php2shell-zeros もその一つで、著者(@acd421、エージェント支援での作業と明記)が4項目を挙げている。

項目ごとに、PHPへ届け出済みかと、どの状態まで示せているかが違う。確定といえるのは、修正の際に新しく入ったバグ(リグレッション。直すつもりが別の不具合を生むこと)1件だけだ。RCEだとする残り2項目は正式な届出がなく、第三者が同じ条件で追試できない。

著者の呼称主張の中身届出状況示せている範囲
Zero 1(セッション処理の抜け)パッチ後の8.5.12で未認証RCEとセッション消去が残る未届。調整中の開示として保留著者の環境でのログのみ。外部の追試なし
Zero 2(GCの二重解放リグレッション)修正に伴い混入したバグを突いてサーバーを落とせる元になったバグは別人(evankford)がphp-src #24488 / PR #24494として同日に届け出済みリモートからのクラッシュ(DoS)まで。標準ビルドではRCEへの格上げは構造的に無理だと著者自身が明記
Zero 4(unserializeの解放後使用)パッチ後の8.5.12で解放後使用(UAF)が起きる未届。初実証だと主張ASAN(メモリ異常を検出するデバッグ用ビルド)でのみ再現。通常ビルドでは同じ入力でも表面化しないと著者が明記
Zero 3(パッチの効き目の分析)新しい脆弱性の指摘はなし。パッチが実際に塞いだ範囲の分析該当なし分析のみ

確定といえるZero 2のリグレッションは、GC(ガベージコレクション。使われなくなったメモリを自動で回収する仕組み)がSimpleXMLの内部テーブルを二重に解放してしまうもので、別の研究者evankfordがPHP本体に正式に届け出ている。ただし著者自身の分析でも、標準ビルドでの影響はクラッシュ・サービス停止(DoS)どまりだ。そこからコード実行まで持っていく手立ては、ZendMM(PHPのメモリ管理機構)側の保護で防がれる。RCEには至らない。

残るZero 1とZero 4は未届で、著者の環境のログかデバッグ専用ビルドでの再現どまりだ。とくにZero 4はASAN付きビルドでしか再現せず、通常ビルドでは表面化しない。自己公開・エージェント支援・正式な届出なしという条件が重なるので、今の時点では確認された脆弱性というより追試待ちの主張だ。著者も公開の判断は協調的脆弱性開示(CVD。報告先と調整しながら時期を決める開示)として保留している。

管理者がいま取るべき対応

確定しているphp2shell本体への対応を優先する。「まだ残る」という主張は確度が低く、更新を遅らせる理由にはならない。公式はどちらのCVEについても「更新だけが唯一の完全な対策」と明記していて、以下の設定はあくまで更新できない場合の暫定策だ。

対応内容
バージョン更新8.5.12・8.4.27・8.3.36・8.2.35のいずれかへ上げる。共有ホスティングやマネージドの場合は、ホスティング側がパッチ適用済みかを確認する
古い系列7.4・8.0・8.1は更新が限られ、5系は修正がない。該当するなら移行か、WAF(Webアプリの前段で不正なリクエストを弾く仕組み)での緩和を検討する

更新できない場合の暫定策は、公式アドバイザリがCVEごとに挙げている。いずれも完全ではない。

CVE更新できない場合の暫定策(公式アドバイザリ)
CVE-2026-109618管理者側で memory_limit=-1(無制限)を強制するのが主要な設定緩和策。あわせて post_max_size を小さく保ち、フロント側でリクエストサイズやmultipartを絞る。RLIMIT_AS・RLIMIT_DATA は mmap() を失敗させるため使わない
CVE-2026-109619PHP 8.5は fatal_error_backtraces=0、セッション側は session.upload_progress.enabled=0 を管理者側で設定し、全ワーカーを再起動する。どちらの設定も片方のきっかけしか塞がない

CVE-2026-109618で memory_limit を無制限にするのは直感に反するが、この脆弱性の起点がメモリ不足時の中断そのものなので、公式はその中断を起こさせないことを主要策に挙げている。

WordPressなどCMSを運用している場合も、脆弱なのはアプリではなく動かしている側のPHP本体なので、プラグインやテーマの更新ではなくPHPそのもの(多くはホスティングの管理画面でのバージョン切り替え)を確認する(Codeableの解説)。