PHPの重大な脆弱性php2shell、対象サーバーの見分け方と更新・緩和策
この記事で分かること
- Webサーバーで動くPHPなら、構成を問わず対象。8.5.12・8.4.27・8.3.36・8.2.35(ディストリビューションのPHPは各社の修正済みパッケージ)にすぐ更新する
- 2件(CVE-2026-109618、CVE-2026-109619)とも、認証なしのリクエストだけで任意のコードを実行されうる。深刻度はCVSS v4.0で9.2
- Apacheのmod_phpが一番危なく、アプリのコードが動く前の1リクエストで攻撃が成り立つ。アプリの側の入力の検査では防げない
- 修正版の公開後に攻撃ツールが公開され、WordPressやLaravelなど11のアプリで認証なしのコード実行が確かめられている
- 設定による緩和策は一部の経路を塞ぐだけで、公式は更新だけが完全な対策としている。PHP 8.1以前は公式の更新の対象外
目次(15項目)
PHPの開発チームは10月21日、認証なしで任意のコードを実行されうる脆弱性2件を直した修正版を出しました。「php2shell」とも呼ばれています。修正版と同時に出た公式のアドバイザリをもとに、自分のサーバーが対象か、何から手を付ければよいかを順に確かめます。
何が起きたのか
予告から修正版の公開までは1日ほどでした。その間に情報が漏れ、攻撃の報告も出ています。時刻は日本時間です。
| 日時 | 出来事 |
|---|---|
| 10月20日 | PHPが重大な脆弱性2件の修正版を翌日に出すと予告。詳細は伏せたまま |
| 10月20日〜21日 | 情報が予定より早く出回る。攻撃のデモ動画が投稿され、後に削除された |
| 10月21日14時 | GMO Flatt Securityが、悪用できると主張するコードが出回り始めたと追記 |
| 10月21日15時〜22時台 | 国内でサービスやサイトの停止、緊急メンテナンスの告知が相次ぐ |
| 10月21日16時43分(協定世界時7時43分) | Cloudflareが、PHPのサイトへの初期の攻撃を報告(Sansecによる) |
| 10月21日夜(予定は23時) | 修正版と公式のアドバイザリを公開 |
| 修正版の公開後 | 技術的な解説と攻撃ツールが公開される |
国内ではBASEやCygamesなどが修正版より前にサービスを止めました。piyologの集計では、21日22時台までに停止や緊急メンテナンスを告知した組織は54に上ります(停止の理由にPHPを挙げていない告知も含みます)。
自分のサーバーは対象か
Webで動いているPHPは全て対象
公式のアドバイザリは、影響を受けるものを「Webのリクエストを処理する全てのPHPの導入」としています。WordPress、Drupal、Magento、LaravelのようなPHPのアプリを動かしているサーバーは、アプリの種類を問わず対象です。
アドバイザリによると、攻撃がどこまで確かめられたかは、構成ごとに次のように違います。
| 構成 | 確かめられた状況 |
|---|---|
| Apache mod_php | 2件とも攻撃を確認。公式が一番危ないとしている |
| PHP-FPM | 2件目で攻撃を確認(アプリ側に条件に合う処理があること)。1件目は完全な攻撃はまだ示されていない |
| FrankenPHP | 1件目はソースの分析で影響を受けるとみられる(未検証)。2件目は既定の設定で使われる処理が見つかっていない(影響がないとは言えない) |
| LiteSpeed(LSAPI) | 1件目は影響を受けるとみられる(未検証)。2件目は条件次第の候補 |
「未検証」や「見つかっていない」は安全という意味ではなく、どの構成でも更新が必要です。
サイトやサーバーでPHPが動いているかの見分け方
外からは応答のヘッダーが手がかりになります。PHPのマニュアルによると、既定で有効な設定expose_phpがオンのPHPは、版の入ったX-Powered-Byのヘッダーを応答に付けます。検証した環境(PHP 8.3.6)の組み込みのWebサーバーでも、既定ではX-Powered-By: PHP/8.3.6が付き、無効にすると付きませんでした。この設定はphp.iniで無効にできるので、ヘッダーがなくてもPHPが動いていることがあります。
サーバーにログインできるなら、php -vで版が分かります。表示されるのはコマンドラインのPHPの版です。FPMやApacheのモジュールのPHPは、パッケージの一覧(Ubuntuならdpkg -l | grep php)でも確かめてください。
修正版の番号と、ディストリビューションのPHPの確かめ方
公式の修正版は次の4つで、2件の修正は同じ版に入っています。
| 系列 | 修正版 |
|---|---|
| PHP 8.5 | 8.5.12 |
| PHP 8.4 | 8.4.27 |
| PHP 8.3 | 8.3.36 |
| PHP 8.2 | 8.2.35 |
PHP 8.2は2026年12月31日でサポートが終わり、以後はセキュリティの修正も出ないため、公式はサポート中の版への移行を計画するよう求めています。
LinuxのディストリビューションのPHPは、この番号と比べても判断できません。ディストリビューションは版の番号を変えずに修正を取り込むことが多く、例えばUbuntu 24.04のPHPは、パッケージの版が8.3.6-0ubuntu0.24.04.12です。修正は各社に事前に渡されていて、UbuntuはUSN-8948-1で修正済みのパッケージを出しました。各社のセキュリティ情報で確かめてください。
次の3つに当たる場合は、上の修正版をそのまま入れるだけでは済みません。
- PHP 8.1以前: PHPの開発チームからの更新はありません。今回は深刻さを考えて7.4、8.0、8.1向けに最小限の修正をソースで用意しましたが、公式は長期サポートの提供元に問い合わせるか、サポート中の版に上げるよう求めています
rpms.remirepo.netのパッケージ: ボランティアが運営しているリポジトリで、公式によると、この日は更新が出ません。ディストリビューションのパッケージか、ソースからのビルドに切り替えるよう勧めています- 製品や機器の内部のPHP: IPAは製品やネットワーク機器の中で使われているPHPにも注意を促しています。利用者からは中のPHPが見えないことがあるので、製品のマニュアルや開発元のセキュリティ情報を確かめてください
どんな脆弱性なのか
2件とも、認証なしのリクエストを送るだけで、Webサーバーのワーカーの権限で任意のコードを実行されうるものです。深刻度はどちらもCVSS v4.0で9.2(Critical)です。

1件目:メモリ不足で処理が途中で止まる(CVE-2026-109618)
PHPはメモリが足りなくなると、その場で処理を打ち切ります。公式によると、このときリクエストの内部のデータが作りかけのまま残り、後片付けの処理がそれを正しいデータとして扱ってしまいます。メモリ不足を起こすきっかけは、multipartの本文(ファイルのアップロードなどで使う形式)の解析などです。公式はmod_phpで、既定の入力とメモリの上限のまま、HTTP越しにコードの実行まで確かめています。
修正版ではメモリ不足のときに安全な位置まで処理を進めてから止めるように変わりました。
2件目:前のリクエストの状態が残る(CVE-2026-109619)
PHPのワーカーは1つのプロセスで複数のリクエストを順に処理します。公式によると、致命的なエラー(メモリ不足を含む)で終わったリクエストの内部の状態が、メモリを解放した後も残ることがあります。同じワーカーが次に処理したリクエストが、初期化される前にその状態を使ってしまう、というのが2件目です。
確かめられた経路の1つは、セッションのアップロード進捗の機能(session.upload_progress)を使うものです。この機能は既定で有効で、アプリがsession_start()を呼んでいなくても使われるため、既定の設定のまま成り立ちます。PHP 8.5では、致命的なエラーのバックトレース(fatal_error_backtraces)を経由する経路も確かめられています。
なぜ急ぐ必要があるのか
アプリの防御が効く前に攻撃される
公式が一番危ないとしているmod_phpでは、認証のない1リクエストで、アプリのコードが1行も動く前に攻撃を始められることが実証されています。脆弱性はPHPそのものにあるので、WordPressやLaravelなどのアプリが入力を検査していても、アプリのコードに問題がなくても、攻撃は防げません。Sansecも、攻撃は自社の防御製品より前に届くとして、自社のルールの提供を待たずに更新するよう呼びかけています。
CVSS 9.2を下げている2つの条件と、その限界
満点の10.0でないのは、攻撃の複雑さが高い(AC:H)ことと、攻撃に前提条件がある(AT:P)ことの2つで点数が下がっているためです(ベクトルは2件ともAV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H)。例えば2件目は、状態を残すリクエストとそれを使うリクエストが、同じワーカーに当たる必要があります。
ただし公式は、ワーカーの数や通信の量は攻撃の試行回数を増やすだけで、条件そのものは消えないとしています。サーバーの台数やワーカーを増やしても、安全にはなりません。「CVSS 10.0」とする報道もありましたが、PHPの評価は当初から9.2です。
攻撃ツールが公開されている
IPAは、攻撃者が極めて短時間で攻撃を実行する可能性があるとして、修正版をすぐに適用できるよう準備を求めていました。
修正版の前は実際の悪用について見方が分かれていました。IPA、watchTowr、Huntressは20〜21日の時点で確認していないとし、TenableはCloudflareのCTOが初期の攻撃を見ていると述べたと伝えています。
修正版の公開後、攻撃ツールの作者とされるCalifは、11のアプリで認証なしのコード実行を確かめました。Sansecによると、対象にはWordPress 7.1.2、Drupal 11.4.3、Laravel 13.11、Magento 2.4.9などが含まれます。技術的な解説と攻撃ツールが公開されたので、大規模な悪用が起きるとSansecはみています。公開後の悪用の報告と更新後の確かめ方は、続報にまとめました。
何をすればよいか
- PHPを使っているものを洗い出す: IPAは開発・運用しているプログラムのうち、PHPを使っているものの棚卸しを求めています。自社のサーバーのほか、PHPを中で使っている製品や機器も対象です
- 修正版に更新する: 上の表の版か、ディストリビューションの修正済みパッケージにします。PHP-FPMやApacheを再起動して、全てのワーカーが新しい版で動いていることを確かめます
- すぐに更新できないなら、緩和策をかける: 下の設定で、確認された経路を減らします。更新するまでのつなぎです
- 侵入に備える: ログを保全し、侵入された場合の被害を小さくする準備をします
すぐに更新できないときの緩和策
公式のアドバイザリの緩和策は、2件それぞれに分かれています。どれも特定の攻撃の経路を減らすだけで、これで安全になるわけではないと公式は明記しています。
1件目(メモリ不足)への緩和策は次のとおりです。
| 設定 | 注意すること |
|---|---|
memory_limit=-1 | アプリが上書きできない場所(FPMのプールやApacheの設定のphp_admin_value)で設定し、ほかの設定が有限の値に戻していないかも確かめる。それでも、もとの割り当ての失敗は脆弱な処理に届きうる |
post_max_sizeを小さくする | ファイルのアップロードが要らないアプリは8M、要るアプリは32M。upload_max_filesizeはそれより小さくする |
| Webサーバーやプロキシで上限をかける | 本文の大きさ、入力の項目数、multipartの部分の数、ヘッダーの数、入れ子の深さ。Content-Lengthが使えないリクエストも対象にする |
multipart/form-dataを拒否する | ファイルのアップロードなどでmultipartを使わないアプリだけ。Sansecによると、知られている攻撃のきっかけは全てこの形式で届く |
| コンテナやcgroupでメモリの上限をかける | RLIMIT_ASやRLIMIT_DATAは脆弱な割り当ての失敗を起こしうるので、代わりに使わない |
memory_limit=-1は1つのリクエストがサーバーのメモリを使い切れるようにする設定でもあります。Sansecは短期の対策として、メモリの使用量を見張りながら使うよう書いています。
2件目(残る状態)への緩和策は次のとおりです。
| 設定 | 注意すること |
|---|---|
session.upload_progress.enabled=0 | php.ini、FPMのプール、サーバーの設定など、リクエストの解析より前に効く場所で設定し、全てのワーカーを再起動する。ini_set()やFPMの.user.iniでは効かない。確認された経路は塞げるが、ほかの変種は防げない |
fatal_error_backtraces=0 | PHP 8.5だけ。全てのワーカーを再起動する |
FPMのpm.max_requests=1 | 性能が許す場合。1リクエストごとにワーカーを入れ替える(GHSA-6wmf-4rv5-p3rpに記載) |
| 初期化の前に警告を出す設定を消す | リクエストごとに当てている設定のうち、無効なものや非推奨のもの。error_reportingやdisplay_errors、@で警告を隠しても効かない |
| 攻撃者が起こせる致命的なエラーを直す | 実行時間切れや、コールバック、アップロードや取り込みの処理、後片付けでの失敗を含む |
session.upload_progress.enabledが既定で有効かどうかは、手元のPHPで確かめられます。検証した環境(Ubuntu 24.04.5 LTS、PHP 8.3.6のCLI)では、php.iniを読まない状態(-n)の組み込みの既定値は次のとおりでした。
$ php -n -r 'foreach (["session.upload_progress.enabled","memory_limit","post_max_size","upload_max_filesize"] as $k) printf("%s = %s\n", $k, var_export(ini_get($k), true));'
session.upload_progress.enabled = '1'
memory_limit = '128M'
post_max_size = '8M'
upload_max_filesize = '2M'
session.upload_progress.enabledは'1'(有効)で、アドバイザリの「既定で有効」と一致します。CLIの値はWebサーバーで動くPHPの値と同じとは限りません。Webで使っている設定を見るには、FPMやApacheの設定ファイルを読むか、管理者だけが開ける場所でphpinfo()を出します。
侵入された場合に備える
予告から更新までに届いたアクセスのログは、更新を終えたサーバーでも、消える前に保全しておいたほうがよさそうです。
GMO Flatt Securityは、パッチの適用とは別に、サーバーでコードを実行された場合の被害を減らす準備を挙げています。サーバーに置くデータを必要な分に絞る、クラウドのIAMロールやサービスアカウントの権限を絞る、侵入の有無を後で調べられるよう、ログが記録され改ざんされにくい形で残っているかを見直す、の3つです。
検証環境
- 最終検証日
- 試した環境
- Ubuntu 24.04.5 LTS
- PHP 8.3.6 CLI(パッケージ 8.3.6-0ubuntu0.24.04.12)
更新履歴
- Ubuntuの修正済みパッケージ(USN-8948-1)が出たことを反映し、修正版の公開後の動きをまとめた続報へのリンクを足した
- サーバーやサイトでPHPが動いているかの見分け方(`php -v`、パッケージの一覧、`X-Powered-By`のヘッダー)を、PHPのマニュアルと手元の検証で確かめて追記した
誤りや古くなった情報に気づいたら、Xで教えてください。


