0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実測検証】PHP2Shell(CVE-2026-109618 / 109619)を「パッチなし」で防ぐ設定・防げない設定

0
Last updated at Posted at 2026-10-25

php2shell 回避策(パッチなし):PHP 設定とサーバ側設定

パッチを当てられない環境で、どの設定がどの段階で攻撃を阻止するか。実測はこのラボ(mod_php・1 worker・PHP 8.3 / 8.4 / 8.5)で行ったものだけを「実測」と書き、それ以外は未検証と明記する。

1. 実測で攻撃を阻止した設定

設定 攻撃を阻止できる段階 根拠
session.upload_progress.enabled=Off Stage 1 の heap leak が成立しない 実測(upload_progress_off)
session.use_strict_mode=1 同じく heap leak が失敗 実測(strict_mode_on)
memory_limit=-1 OOM が起きないので Stage 1 が失敗 実測
post_max_size=8M 12,655,437 B の圧力 POST が受理されない 実測
display_errors=Off heap leak が失敗(理由は未特定) 実測(display_errors_off)

memory_limit は「OOM しない値まで上げる」という意味。-1 だけ実測で、128M などの中間値は未検証。上げると別の DoS 耐性は下がるので、用途に合わせて決める。

2. 109619 path 2(pre-RINIT callback)

専用ラボで 11 通りを実測した。結論は 「成立を阻止できるのは 2 つだけ」。

設定 / 状態 path 2 の結果(実測) 判定
.htaccess を無効化(AllowOverride None)または .htaccess 削除 unserialize_callback_func が空になり nonce なし。session_start() を呼ぶエンドポイントでも同じ。 止まる
セッションレコードを作らせない(Web から書けない保存先) 未知クラスが存在せず nonce なし(callback は arm 済みでも成立しない)。 止まる
session.upload_progress.enabled=Off アプリが session_start() を呼ばないエンドポイントでは止まる。呼ぶ場合は nonce が出る。 条件付き(自動トリガーを無効化するだけ)
session.use_strict_mode=1 攻撃者が用意した SID のレコードはそのまま読まれ、nonce が出る。 止まらない
アプリが ini_set('unserialize_callback_func', 'system') する .htaccess を無効化しても session_start() で成立(nonce あり)。ini_set が upload-progress の読み込みより後なら成立しない。 アプリ次第

path 2 の成立を阻止するのはこの 2 つ。 ① callback を arm させない(.htaccess を無効化する・unserialize_callback_func を設定しない)② セッションレコードを作らせない。upload_progress Off と strict_mode は単独では不十分(実測)。.htaccess を無効化してもアプリの ini_set で再び有効になるため、コード側も確認する。

3. 効果がなかった / 当てにしない設定

設定 結果 理由
disable_functions=system,exec,… 止まらない(実測) チェーンは zif_system のアドレスを直接呼ぶ。名前での無効化は関係しない。
session.auto_start=On だけ 止まらない / 復活もしない 必要なのは upload_progress。auto_start は代替にならない(実測)。
expose_php=Off・バージョン非表示 攻撃は止まらない blind でもバージョンは推定できる。検知の補助にしかならない。
MaxRequestWorkers を増やす 止まらない worker pinning は「空きを 1 個」にすれば成立する。台数を増やすと狙いやすくなるだけ。

4. ini の例

; サーバ全体の php.ini に置く。.user.ini / .htaccess は Web から
; 書ける場合があり、攻撃側に書き戻されるため、当てにしない。
session.upload_progress.enabled = Off
session.use_strict_mode        = 1
session.save_path              = /var/lib/php/sessions
session.cookie_httponly        = 1
open_basedir                   = /var/www/html:/var/lib/php/sessions:/tmp
post_max_size                  = 8M
memory_limit                   = 128M   ; -1 は実測。中間値は未検証
display_errors                 = Off    ; leak 失敗の実測あり(理由不明)

読み込み順に注意。 conf.d はファイル名順で後のものが勝つ。反映後は必ず Web の SAPI で値を確認する。

5. PHP の外側(Apache / FPM / ネットワーク)

設定 効果 状態
LimitRequestBody 8388608 12 MiB 級の POST を入口で拒否。PoC は本文サイズを変えてくるので恒久策ではない。 Apache の仕様
RequestReadTimeout body=10,MinRate=500(mod_reqtimeout) worker pinning(Content-Length: 6000000 を宣言して 2 KB だけ送り保持)を阻止する。成功率を下げる。 Apache の仕様
FPM request_terminate_timeout / pm.max_children 長時間の保持と多重化を制限。pinning の土台を弱める。 設計上の効果(未検証)
外向き通信の制限(egress) 逆シェル(/dev/tcp)や第二段の取得を阻止する。 設計上の効果(未検証)
/tmp の noexec・auditd EXECVE 攻撃コードの実行と実行後の痕跡確保。 設計上の効果(未検証)

6. 位置づけ

これは回避策であり、修正ではない。 メモリ破壊そのものは残る。設定は「攻撃の成立条件(OOM・upload progress・セッション初期化)を排除する」だけで、バージョン・SAPI・アプリの実装次第では対策にならない。未検証の組み合わせを「安全」と断定しない。最終的にはベンダーパッチを当てる。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?