PHP2Shell の検知と多層防御|WAF・IDS(Suricata/Sigma/ModSecurity)・EDR・コンテナの硬化まで
修正版を入れるまでの間、何層で止め、どこで気づくか。CDN・WAF、Web サーバーの制限、PHP と FPM の設定、cgroup・seccomp、IDS・Sigma・EDR・SIEM の相関まで、PHP2Shell に合わせた多層防御を技術者向けにまとめた。
PHP2Shell の検知と多層防御|WAF・IDS(Suricata/Sigma/ModSecurity)・EDR・コンテナの硬化まで
- 層は5つ。CDN・WAF、Web サーバー、PHP と FPM、実行環境(コンテナ・カーネル)、検知と対応
- multipart を使わないアプリなら、手前で multipart を止めるのが効く(公式の勧告)
- ModSecurity は multipart のとき REQUEST_BODY が空になり、本文を見るルールが発火しない落とし穴がある
- いちばん確かな検知は「PHP のワーカーがシェルを起動した」という子プロセスの記録
3. PHP と FPM の設定
- session.upload_progress.enabled=0:109619 のセッションの経路をふさぐ
- fatal_error_backtraces=0(8.5):109619 のもっとも強い経路をふさぐ
- memory_limit=-1(管理者の設定で固定):109618 の既知の経路を止める
4. 実行環境の硬化
RCE が成功しても、被害を小さくする層だ
- cgroup の memory.max:コンテナやサービスのメモリの上限。完全な対策ではないが、暴走を抑える
- 読み取り専用のルートファイルシステム:書き込みを、アップロードの場所と一時ファイルの場所だけにする。その場所では PHP を実行させない
- seccomp・AppArmor・SELinux:ワーカーが execve で外のプログラムを起動できないようにする
優先順位
- 1:修正版への更新(配布元のパッケージなら、更新と再起動)
- 2:CDN・WAF のマネージドルールの確認と、オリジンの直接到達の遮断
- 3:upload_progress・fatal_error_backtraces の無効化、本文の上限
PHP2Shell の根本の対策は、修正版への更新だけだ。ただ、検証やメンテナンスの枠の都合で、すぐには入れられない環境もある。そのあいだ、何層で止め、どこで気づくか。公式の勧告と、公開されている検知のルールをもとに、多層防御(defense in depth)の組み立て方をまとめた。
- 層は5つ。CDN・WAF、Web サーバー、PHP と FPM、実行環境(コンテナ・カーネル)、検知と対応
- multipart を使わないアプリなら、手前で multipart を止めるのが効く(公式の勧告)
- ModSecurity は multipart のとき REQUEST_BODY が空になり、本文を見るルールが発火しない落とし穴がある
- いちばん確かな検知は「PHP のワーカーがシェルを起動した」という子プロセスの記録
- 公開されている検知のルールは非公式。検証の環境で試してから入れる
全体像
どの層も、単独では不完全だ。WAF はすり抜けがありうるし、PHP の設定は特定の経路しかふさがない。層を重ねて、更新までの時間をかせぎ、すり抜けたものを検知で拾う。
1. CDN・WAF
マネージドルール(仮想パッチ)
Cloudflare などの CDN は、PHP2Shell 向けのマネージドルールを急いで配った。報告によると、Cloudflare は無料のプランを含めて規則を入れている。CDN を通しているなら、マネージドルールが有効になっているか、ログで発火しているかを確かめる。
WAF は、オリジン(本物のサーバー)の IP に直接届く通信には効かない。オリジンのファイアウォールで、CDN の IP の範囲以外からの 80・443 番を閉じておく。
multipart を止める
公式の勧告(109618)は、アプリが multipart/form-data を使わないなら、手前で止めるよう勧めている。ファイルのアップロードがない API や、管理画面だけが multipart を使うサイトなら、パスごとに許可する形にできる。
2. Web サーバーの制限
OOM を起こしにくくするため、PHP に届く前に、本文とヘッダーの大きさを絞る。
nginx の例:
# 本文の上限(アップロードが要らないなら小さく)
client_max_body_size 8m;
# ヘッダーの大きさの上限
large_client_header_buffers 4 8k;
Apache の例:
# 本文の上限(バイト)
LimitRequestBody 8388608
# ヘッダーの数と1つの長さ
LimitRequestFields 50
LimitRequestFieldSize 8190
値はアプリに合わせる。小さくしすぎると、正規のアップロードやフォームが失敗する。
3. PHP と FPM の設定
| 設定 | 狙い | 注意 |
|---|---|---|
session.upload_progress.enabled=0 | 109619 のセッションの経路をふさぐ | 進み具合の表示を使うアプリでは動かなくなる |
fatal_error_backtraces=0(8.5) | 109619 のもっとも強い経路をふさぐ | |
memory_limit=-1(管理者の設定で固定) | 109618 の既知の経路を止める | メモリを使い切る危険。長くは続けない |
post_max_size を控えめに | 本文の解析の量を減らす | |
max_input_nesting_level を下げる | 入れ子の項目名による OOM を起こしにくくする | 既定は 64 |
max_input_vars・max_file_uploads を絞る | 項目数・パート数を絞る | |
pm.max_requests=1(FPM) | 1回ごとにワーカーを作り直し、状態の持ち越しをなくす | 性能が大きく落ちる。負荷の低いサイト向け |
設定は php.ini か、FPM のプールの php_admin_value、Apache の php_admin_value で行い、すべてのワーカーを再起動する。ini_set() や .user.ini では効かない。
プロセスのメモリの上限を RLIMIT_AS や RLIMIT_DATA でかけると、攻撃に必要な確保の失敗を、かえって起こしやすくする。公式の勧告も使わないよう書いている。上限は cgroup でかける。
4. 実行環境の硬化
RCE が成功しても、被害を小さくする層だ。
- cgroup の
memory.max:コンテナやサービスのメモリの上限。完全な対策ではないが、暴走を抑える - 読み取り専用のルートファイルシステム:書き込みを、アップロードの場所と一時ファイルの場所だけにする。その場所では PHP を実行させない
- seccomp・AppArmor・SELinux:ワーカーが
execveで外のプログラムを起動できないようにする - 外向きの通信の制限(egress):ワーカーから外への接続を、必要な宛先だけにする。逆接続のシェルや、追加の荷物の取得を止める
disable_functions:exec・system・passthru・shell_exec・proc_open・popenなどを止める。ただし、メモリの破壊からの RCE は PHP の関数を経由しないことがあるので、これだけには頼らない- 秘密情報の置き場所:環境変数や設定ファイルの秘密は、ワーカーの権限で読める。侵害が疑われたら、鍵と資格情報を入れ替える
5. 検知と対応
ネットワーク(IDS・WAF のログ)
コミュニティから、Suricata・Snort・ModSecurity・Sigma のルールが公開されている。シグネチャの数や SID はリポジトリごとに違い、互いに入れ替えられるものではない。見ているのは、おおむね次の特徴だ。
- 項目名が数 MB ある
application/x-www-form-urlencodedの本文 - 名前が空の項目にバイナリが入った multipart
PHP_SESSION_UPLOAD_PROGRESSを含む POST- PoC の既定の User-Agent
公開されている検知の解説によると、ModSecurity は multipart の本文のとき REQUEST_BODY が空になる。本文を REQUEST_BODY で見る形のルールは、multipart では発火しない。早い時期に入れた本文ベースのルールは、見直しが要る。
ホスト(EDR・監査ログ)
いちばん確かな検知は、子プロセスの記録だ。Web のワーカー(php-fpm・apache2・httpd・php-cgi)が、sh・bash・dash を起動するのは、ふつうのアプリではまず起きない。Sigma の process_creation のルールなら、次のような形になる。
title: Web の PHP ワーカーからのシェルの起動
logsource:
category: process_creation
product: linux
detection:
parent:
ParentImage|endswith:
- '/php-fpm'
- '/apache2'
- '/httpd'
- '/php-cgi'
child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
condition: parent and child
level: high
PHP-FPM のマスターの名前は、配布元で php-fpm8.3 のように版が付くことがある。環境に合わせて名前を足す。アプリが正規に外のコマンドを呼ぶ場合(画像の変換など)は、例外として登録する。
SIEM での相関
単独では弱い手がかりも、同じ時刻・同じワーカーで重なれば強くなる。
| 手がかり | 出る場所 |
|---|---|
| 異常に大きい POST・multipart | アクセスログ・WAF |
Allowed memory size ... exhausted と「Unknown on line 0」 | PHP のエラーログ |
ワーカーの異常終了(Apache の AH00052) | Web サーバーのエラーログ |
| 直後の HTTP 500 | アクセスログ |
| 異常に長い PHPSESSID の Set-Cookie | 応答のログ(取っていれば) |
| ワーカーからの子プロセス・外への通信 | EDR・監査ログ・ファイアウォール |
Datadog は、攻撃が HTTP 200 を返したままワーカーを動かし続けることがあると指摘している。状態の番号だけで判断しない。
優先順位
| 順 | やること | 効き目 |
|---|---|---|
| 1 | 修正版への更新(配布元のパッケージなら、更新と再起動) | 根本の対策 |
| 2 | CDN・WAF のマネージドルールの確認と、オリジンの直接到達の遮断 | 手前で大半を止める |
| 3 | upload_progress・fatal_error_backtraces の無効化、本文の上限 | 既知の経路をふさぐ |
| 4 | 子プロセスの検知(Sigma・EDR) | すり抜けに気づく |
| 5 | 侵害の調査と、鍵・資格情報の入れ替え | 入られていた場合の後始末 |
用語
| 用語 | 意味 |
|---|---|
| 多層防御 | 1つの対策に頼らず、複数の層を重ねる考え方 |
| 仮想パッチ | 本体を直す前に、WAF などで攻撃の形を止めること |
| オリジン | CDN の後ろにある、本物のサーバー |
| IDS | 侵入の兆しを通信から見つける仕組み(Suricata・Snort など) |
| Sigma | ログの検知ルールを、製品に依存しない形で書く決まり |
| EDR | 端末やサーバーの動き(プロセス・通信)を記録し、不審な動きを見つける仕組み |
| SIEM | 複数のログを集め、組み合わせて分析する仕組み |
| egress | サーバーから外へ出ていく通信 |
よくある質問
WAF を入れていれば更新しなくても大丈夫ですか?
大丈夫ではありません。
WAF はすり抜けがありえますし、オリジンに直接届く通信には効きません。
更新までのつなぎとして使ってください。
disable_functions で exec などを止めれば防げますか?
被害を小さくする効果はありますが、防ぎきれません。
メモリの破壊からのコードの実行は、PHP の関数を経由しないことがあるからです。
いちばん確実な検知の方法は何ですか?
Web の PHP のワーカーが、シェル(sh・bash など)を子プロセスとして起動した記録です。
ふつうのアプリではまず起きないので、誤検知が少なく、強い手がかりになります。
参考にした情報
- GitHub Advisory:RCE via OOM corruption(GHSA-w8hw-w9fx-j79w / CVE-2026-109618)(英語)
- GitHub Advisory:RCE via stale global state(GHSA-6wmf-4rv5-p3rp / CVE-2026-109619)(英語)
- Datadog Security Labs:PHP2Shell の分析(英語)
- JPCERT/CC:PHPにおける複数の脆弱性に関する注意喚起(JPCERT-AT-2026-0033)
- GitHub Gist:PHP2Shell: Detection Opportunities(英語)
- nanosek:PHP2Shell の Cloudflare WAF ガイド(英語)
- Sophos:Proof-of-concept exploit released for PHP vulnerabilities(英語)
- Apache HTTP Server:core のディレクティブ(LimitRequestBody など)(英語)
- nginx:ngx_http_core_module(client_max_body_size など)(英語)
- php.net:FPM の設定(pm.max_requests)
2026年10月22日時点の公開情報にもとづく。攻撃のコード(PoC)の中身は、悪用を助けないよう載せていない。最新の情報は、PHP の公式の勧告と JPCERT/CC を確認すること。
自社のサーバーの構成で、どの層から手を付けるべきかを、構成を聞いてから伝える。相談は無料。
無料で相談する


