PHPの重大な脆弱性「PHP2Shell」を狙う攻撃を検証、公開サーバーがHTTP500エラーを44回返した原因はメモリ不足だった。POSTの封筒が飛び込み、メモリがあふれたPHPサーバーの横にHTTP500の警告が出ているイメージ。

PHPの重大な脆弱性「PHP2Shell」を狙う攻撃を検証、公開サーバーがHTTP500エラーを44回返した原因はメモリ不足だった

正常に表示できていたPHPのページが、攻撃POSTを受けてHTTP500を返した。エラーログには「Allowed memory size of 134217728 bytes exhausted」。我々が観測用に公開しているPHPサーバーで、設定した128MiBのメモリ上限に達し、リクエストの処理が止まった。

前回は、PHPの重大な脆弱性群「PHP2Shell」を狙うPOSTから、サーバーを他の相手への攻撃に使うプログラムの取得命令を見つけた。その後も観測を続けると、10月24日と26日にはメモリ不足が繰り返し発生した。今回は、実際に処理が失敗した場面をログと通信本文から追う。時刻は断りがない限り2026年の日本時間で記す。

正常だったページが、POSTの直後にHTTP500を返した

10月24日8時19分59秒、/index.phpへのGETにはHTTP200が返っていた。続いて同じ送信元からクエリ付きのPOSTが届き、8時20分02秒にメモリ不足の致命的エラーとHTTP500が記録された。

アクセスログの抜粋・整形表示(JST、送信元とクエリを省略)
2026-10-24 08:19:59  GET  /index.php       → 200
2026-10-24 08:20:02  POST /index.php?...  → 500
※時刻はログ出力時刻。POSTの受付時刻は08:20:01。
同時刻のPHPエラーログ(原文、時刻はUTC)
[23-Oct-2026 23:20:02 UTC] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes) in Unknown on line 0

134,217,728バイトは128MiB。さらに12,288バイトを確保しようとして失敗している。この12,288バイトは、PHPが追加で確保しようとした量だ。送られてきたPOSTのサイズを示す値ではない。

通常ページが返る状態から、POSTの処理失敗へ変わった。
10月24日のアクセスログ・エラーログ
08:19:59GETにHTTP200通常ページを返す
攻撃POSTを受信128MiBの上限に到達PHPが致命的エラーを記録
08:20:02POSTにHTTP500要求された処理が失敗

メモリ不足は3つの時間帯に、計44件起きた

10月23日17時39分から26日10時07分までの回収ログで、PHPのメモリ不足は44件あった。すべて修正前のPHP8.3.35で発生し、各時間帯のアクセスログにも合計44件のHTTP500が残っていた。

メモリ不足のエラーは、日をまたいで繰り返していた。
10/24 08:20:02〜08:24:49
メモリ不足 27件
10/24 09:05:51〜09:07:48
メモリ不足 12件
10/26 02:17:12〜02:20:56
メモリ不足 5件

止まったのは、そのPOSTを処理していたPHPの処理だ。最後のエラーの後、10月26日2時21分33秒には、別のPOSTにHTTP200と通常ページが返っている。今回、実際に確認できた影響は、メモリ不足による処理の中断とHTTP500の応答だ。

公開していた環境回収ログで確認した結果
PHP8.3.35(修正前)メモリ不足44件。同じ時間帯にHTTP500が44件
PHP8.3.36(修正を含む)同じ集計期間にメモリ不足の記録なし

2台は別のIPで公開している。攻撃者から同じ本文・同じ回数が届いた条件ではないため、この件数だけで修正の効果を比較することはできない。修正前後に同じ入力を与えた検証は、PHP2Shellの検証記事に掲載している。

POSTの中には、空のファイル項目と深い入れ子があった

10月26日2時17分台の保存パケットを読むと、POSTはmultipart/form-dataだった。multipartは、フォームの項目やファイルを境界で区切って送る形式だ。通信本文には、ファイル名が空の項目や、角括弧で何段も入れ子になった項目名、長いヘッダーが並んでいた。

保存パケットから抜き出したPOSTヘッダー(宛先・クエリ・境界値を省略)
POST /index.php?... HTTP/1.1
Content-Type: multipart/form-data; boundary=[省略]
Transfer-Encoding: chunked
Connection: close

本文を分割して送るTransfer-Encoding: chunkedが使われ、この要求のヘッダーにContent-Lengthはなかった。受信データの量に加え、PHPが項目やヘッダーを内部で展開するときのメモリ消費が問題になる。

PHPの公式勧告は、multipartの多数のヘッダー、空のファイル項目、入れ子の項目名などによって、見かけの入力制限内でもメモリ不足に到達し得ると説明している。今回の本文にもこれらの特徴があり、PHP2Shellを狙った攻撃とみられる。

通信の本文を解析し、PHP内部のデータへ展開する段階でメモリを使う。
01
外部からのPOSTmultipartの本文が届く多数の項目や長いヘッダーを含む
02
PHPの入力処理項目の情報をメモリ上に展開空のファイル項目や入れ子にも管理用の領域が必要
03
今回のログ上限に達して処理を中断致命的エラーを記録し、HTTP500を返した

メモリ不足が、なぜコード実行につながるのか

PHP2Shellのうち、今回の本文と関係するのがメモリ不足時の処理の脆弱性だ。公式勧告によると、修正前のPHPでは、メモリ不足で処理を途中終了した際に、不完全な状態のデータが残る場合がある。続く終了処理がそれを参照すると、攻撃者のコード実行につながり得る。

我々の環境はApacheにPHPを組み込んで動かすmod_phpで、公式が説明する影響対象の構成だった。アプリケーションのコードが動き始める前の、POST本文の解析でも問題が起き得る。

  1. 今回、メモリ不足による処理の失敗は起きた。 PHPの致命的エラーとHTTP500が記録された。
  2. 不正な外部コマンドが実行された形跡はなかった。 対象期間のOS監査ログには、攻撃に対応する実行記録は残っていない。

あわせて読む

届いたPOSTの中身は、ボットの取得命令だった

前回の記事では、受信本文から配布ファイルを追い、他のサーバーへ通信を繰り返すボットの機能を解析した。

メモリ上限を設定していても、更新が必要だ

今回のサーバーには、PHPのメモリ上限128MiBとPOSTの上限8MiBを設定していた。それでも、公開先に届いたPOSTでメモリ不足が発生した。入力の量と、その入力を処理するためのメモリ量は一致しない。

PHPの公式勧告は、この脆弱性への完全な対処として、修正を含むPHPへの更新を求めている。修正を初めて含むのは8.2.35、8.3.36、8.4.27、8.5.12だ。運用環境では、利用中の系列で修正を含むリリースへ更新する。

POST本文のサイズやmultipartの項目数・ヘッダー数を入口で制限することも、負荷を抑える助けになる。今回のようにPHPの処理が失敗しているかは、HTTP500の発生時刻とPHPのエラーログを照合すると追いやすい。

自社システムの脆弱性対応やセキュリティ対策について、お気軽にご相談ください。

SERVICE最新AIペネトレーションテスト悪用される前に、弱点を洗い出す。公開Web・API・クラウド・社内システムまで、合意した範囲だけを、攻撃者と同じ最新のAI攻撃ツールで試します。報告は今日直すものに絞って優先順位をつけ、修正後の再検証まで行います。
ブログ一覧へ