「PHPに重大な脆弱性、世界のウェブサイトの7割が対象」というニュースを見て、最初に思ったのは「うちのブログもPHPだよな」でした。
結論から言います。自分のサーバーには、修正パッケージは来ませんでした。
2017年にさくらのVPSにKUSANAGIで立てたこのブログは、CentOS 7とPHP 7.4のまま動かしていました。どちらもとっくにサポートが切れていて、今回の脆弱性の修正版はPHP 8.2以上にしか出ません。「動いているから」で放置してきたツケが、いちばん嫌な形で回ってきた話です。
この記事では、脆弱性の要点、なぜ更新できなかったのか、更新できないと分かった日のうちに入れた緩和策、そしてKUSANAGI 9への移行を決めるまでを書きます。同じようにVPSでWordPressを動かしている方は、まず php -v を打ってから読み進めてください。
PHP2Shellとは何だったのか|2つのCVEを3行で
細かい技術解説は専門家の記事に譲るとして、自分が把握した範囲で要点だけまとめます。
- CVE-2026-109618とCVE-2026-109619の2件。通称「PHP2Shell」。どちらもCVSS 9.2のクリティカル
- 認証なし・ネットワーク経由でサーバー上のコードを実行される。しかもPHP本体の欠陥なので、WordPressやプラグインをいくら更新しても直らない
- 修正版はPHP 8.5.12、8.4.27、8.3.36、8.2.35の4つ。つまり8.2未満には修正版が存在しない
3つ目が、この記事の全てです。
もう1つ押さえておきたいのが、「誰が直すのか」の違いです。さくらのレンタルサーバーやエックスサーバー、ConoHa WINGのような共用サーバーは、事業者側が夜のうちにPHPを更新していました。古いPHPを使っている人向けに独自の修正を当てた事業者もあります。利用者は何もしなくてよかったわけです。
一方でVPSは、OSから上は全部自分の責任です。さくらからは「【重要】PHPの脆弱性に関するご利用環境の確認のお願い」というメールが来ましたが、中身は「確認してください」であって、誰も代わりにやってくれません。
自分で選んだ構成なので当然なんですが、今回ほど「VPSを選んだ」ことの意味を感じた日はありませんでした。
まず自分のサーバーを見た|kusanagi status で現実を知る
対応に取りかかった日は、何をするにも「今のバージョンは何か」が先です。SSHで入って3つ打ちました。
cat /etc/os-release | head -2
sudo kusanagi status
php -v
結果がこれです。
NAME="CentOS Linux"
VERSION="7 (Core)"
KUSANAGI Version 8.4.5-7
*** (active) php7-fpm ***
PHP 7.4.33 (cli) (built: Nov 1 2023 04:44:51) ( NTS )
CentOS 7、KUSANAGI 8、PHP 7.4。全部、2017年にこのブログを立てたときの構成そのままです。当時の様子はKUSANAGI環境で個人ブログを立ち上げるまで-1から3回に分けて書いていて、読み返すと「最新のKUSANAGIで爆速」みたいなことを嬉しそうに書いています。9年前の話です。
正直に書くと、放置していた自覚はありました。CentOS 7のサポートが2024年6月に終わったことも、PHP 7.4が2022年11月に終わっていたことも、知識としては知っていました。ただ、サイトは普通に表示されるし、WordPress本体もプラグインも管理画面から更新できる。「動いているからいいか」で、毎回後回しにしていました。
言い訳できないのは、WordPressのダッシュボードがずっと教えてくれていたことです。「PHP の更新を推奨」という赤いマークつきのボックスが、ログインするたびに一番上に出ていました。KUSANAGIのセキュリティ状況パネルにも「PHP実行環境:PHP/7.4.33」と書いてあります。
見えていたのに、読んでいなかった。「推奨」という言葉の弱さもあって、プラグインの更新バッジと同じ温度で流していました。あのボックスが言っていた「セキュリティアップデートを受け取れません」は、今回まさにその通りになったわけです。
なぜ詰んだのか|EOLは「修正が来ない」という意味
EOL(End of Life、サポート終了)になれば、セキュリティ修正も来なくなる。それは分かっていました。
ただ、自分の中には「サポートが切れた」と「脆弱性を抱えている」は別の話だ、という線引きがありました。EOLになった瞬間に穴が開くわけではない。既知の脆弱性がなければ、古いバージョンでもすぐに危険になるわけじゃない。だから「次に大きな脆弱性が出たら考えればいい」くらいの温度で構えていました。甘い認識だったと思います。
しかもこの認識は、ここ1〜2年で前提が変わっていました。AIエージェントがコードを読むようになってから、脆弱性が見つかるペースも、見つかった穴を突く攻撃が自動化されるスピードも、人力の時代とは桁が違います。実際、今回の2件を見つけたのもAIを使った調査チームでした。「次に大きな脆弱性が出たら」の「次」が、以前よりはるかに早く、はるかに高い頻度でやってくる。そういう時代に、2017年の構成のまま「まだいいか」と言っていたわけです。
その「次」が来たときの状況が、こうでした。
| 系列 | 修正版 | 状態 |
|---|---|---|
| PHP 8.5 | 8.5.12 | 公式リリース |
| PHP 8.4 | 8.4.27 | 公式リリース |
| PHP 8.3 | 8.3.36 | 公式リリース |
| PHP 8.2 | 8.2.35 | 公式リリース(2026年12月でサポート終了) |
| PHP 8.1 以前 | なし | ソース向けの最小パッチのみ |
自分のPHP 7.4は一番下の行です。PHPの開発チームは7.4と8.0、8.1向けに「最小限の修正を当てたソースコードのブランチ」だけは公開してくれました。ただこれは、自分でコンパイルしてバイナリを差し替える人向けのものです。KUSANAGIのパッケージとして配られるわけではないので、yum update では何も更新されません。
KUSANAGI側の対応も確認しました。プライム・ストラテジーは10月22日の未明までにPHP 8.2から8.5の修正パッケージを出していて、対応はかなり早かったです。ただし対象はKUSANAGI 9です。CentOS 7上のKUSANAGI 8は、もともとPHP 7系までしか載らない設計なので、ここにも修正は来ません。
つまり、こういう状態でした。
- PHPプロジェクト: 8.2以上にしか出さない
- KUSANAGI: 9にしか出さない
- 自分: CentOS 7のKUSANAGI 8でPHP 7.4
逃げ道がどこにもない。これが「詰んだ」の中身です。
ちなみに、レンタルサーバー各社はこの状況に対して独自の対応をしていました。ヘテムルはPHP 7.4にも修正を当て、エックスサーバーも8.1以前に独自修正を検証して順次適用、と発表しています。事業者が大量のユーザーを抱えているからこそできる対応で、VPSで1台を自分で面倒みている人間には、その選択肢はありません。
「動いているから」で先送りしてきた判断の、いちばん高いツケがこれでした。VPSを選んだ時点で、直すのは自分しかいなかったわけです。
当日やった緩和策|更新できないなら攻撃面を減らす
更新できないと分かった時点で、選択肢は3つでした。
- サイトを止める
- 今すぐKUSANAGI 9に移行する
- 攻撃の入口を塞いで時間を稼ぎ、落ち着いて移行する
1は個人ブログとはいえ避けたい。2は半日かかるうえ、焦ってやると別の事故を起こします。なので3を選びました。PHPの公式アドバイザリに「パッチ以外の緩和策」が書かれていたので、それをそのまま自分の環境に当てはめています。
先に書いておくと、これらはあくまで部分的な対策です。 確認されている攻撃経路を塞ぐだけで、別の経路が見つかれば効きません。更新が唯一の完全な対策、というのは公式も明言しています。
php.ini|session.upload_progress を切る、リクエストサイズを絞る
2件のうちCVE-2026-109619は、PHPのセッションにある「アップロードの進捗を記録する機能」が攻撃経路の1つとして確認されています。この機能は既定で有効ですが、WordPressは使っていません。なので切りました。
もう1件のCVE-2026-109618は、メモリ不足を意図的に起こさせる攻撃です。巨大なリクエストや、深くネストしたデータを送りつけるのが手口なので、受け付けるサイズを小さくしておきます。
php.iniに入れたのはこの4行です。
session.upload_progress.enabled = 0
post_max_size = 8M
upload_max_filesize = 4M
max_input_nesting_level = 16
画像のアップロードが4MBまでになりますが、ブログ用途なら困りません。書き換えたら php-fpm を再起動して、php -i で値が変わったことを確認しました。
注意点が1つあって、session.upload_progress.enabled は ini_set() や .user.ini で切っても間に合いません。リクエストの初期化前に効いている必要があるので、php.iniかphp-fpmのpool設定で切ってワーカーを再起動する必要があります。これも公式アドバイザリに書かれていました。
nginx|管理画面以外への multipart POST を 403 にする
2件とも、攻撃には multipart/form-data 形式のPOSTリクエストが使われます。ファイルアップロードで使われる形式です。ブログの読者がこの形式で送ってくるものは、通常ありません。なのでnginxで、管理画面とログイン以外へのmultipart POSTを丸ごと403にしました。
set $block_mp "";
if ($request_method = POST) { set $block_mp "P"; }
if ($content_type ~* "multipart/form-data") { set $block_mp "${block_mp}M"; }
if ($request_uri !~ "^/(wp-admin/|wp-login\.php)") { set $block_mp "${block_mp}X"; }
if ($block_mp = "PMX") { return 403; }
nginxの if は条件を組み合わせられないので、変数に文字を足していって「3条件すべて揃ったら403」という書き方をしています。これを別ファイルにして、サイトの server ブロックから include しました。あわせて client_max_body_size も8mに揃えています。
副作用が1つあります。Contact Form 7のお問い合わせフォームは、送信にmultipartを使います。なので移行までの間、お問い合わせフォームは動きません。個人ブログなので割り切りましたが、問い合わせが収益に直結するサイトなら、フォームのエンドポイントだけ許可リストに足す判断になると思います。
効いているかの確認|curl で multipart と urlencoded を投げる
設定を入れたら、効いているかを確認します。サーバー上から2種類のPOSTを投げました。
curl -s -o /dev/null -w "multipart: %{http_code}\n" -X POST -F "a=b" https://tsukarooohi.com/
curl -s -o /dev/null -w "urlencoded: %{http_code}\n" -X POST -d "a=b" https://tsukarooohi.com/
1つ目がmultipart、2つ目が通常のフォーム形式です。結果はこうでした。
multipart: 403
urlencoded: 200
multipartだけが弾かれて、通常のPOSTは通っています。あわせてサイトの表示と、管理画面へのログインも問題ないことを確認しました。
ここまでで15分くらいです。「更新できない」と分かってから攻撃面を減らすまでが15分で済んだのは、公式アドバイザリに緩和策が具体的に書かれていたのが大きかったです。
ついでに出てきたSSHの指摘|お名前.comの診断とTerrapin
PHPの件と前後して、もう1つ気になっていたものがありました。お名前.comの「ネットde診断」で、このサーバーに対して脆弱性の指摘が出ていたんです。中身はOpenSSH 7.4に対するCVEが17件。CVSS 9.8のものも含まれていて、一覧だけ見るとかなり物騒です。
これもCentOS 7が原因です。CentOS 7のOpenSSHは7.4で止まっていて、Red Hatが修正を遡って当てていた期間も2024年6月で終わっています。
ただ、17件を1つずつ読むと、サーバーに侵入される種類のものはほとんどありませんでした。
| 分類 | 件数の目安 | 中身 |
|---|---|---|
| scpクライアント側の問題 | 4件 | 悪意あるサーバーに接続したときに影響。公開サーバー側の穴ではない |
| ユーザー名の列挙 | 3件 | 存在するユーザー名を当てられる。鍵認証のみなら実害はほぼない |
| エージェント転送まわり | 2件 | 攻撃者のサーバーに転送した場合の話。これも接続する側の問題 |
| サーバー側で意味があるもの | 2件 | Terrapin攻撃(CVE-2023-48795)と、特殊な設定下での権限昇格 |
CVSS 9.8のCVE-2023-38408も3番目の分類で、こちらが攻撃者のサーバーにエージェント転送した場合にしか成立しません。診断ツールはバージョン番号だけで判定するので、こういう「クライアント側の脆弱性」も一緒に並んでしまいます。
サーバー側で対処する価値があるのはTerrapinです。通信経路に割り込んだ攻撃者が、SSHの暗号方式を弱いものに落とす攻撃で、ChaCha20とCBC系の暗号を使っている場合に成立します。これは設定で潰せるので、sshd_config で暗号方式をAES-GCMとAES-CTRに絞り、MACもSHA-2系だけにしました。
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
ここで1つ、自分の中で引っかかったことがあります。この設定を入れて sshd を再起動するとき、今つないでいるセッションを閉じずに、別のターミナルから新しく接続できるかを確認しました。設定ミスでSSHから締め出されると、VPSのコンソールから復旧する羽目になるからです。基本中の基本なんですが、こういう「切り戻しの道を残してから変える」を、PHPの件でも最初からやっておくべきだったと思いました。
なお、パスワード認証の無効化とrootログインの禁止は、2017年の構築時からやってありました。診断に出た「ユーザー名の列挙」系が実害なしと判断できたのは、ここができていたからです。
OpenSSH自体を新しくするには、結局OSごと変えるしかありません。これもKUSANAGI 9への移行で解決する話でした。
結局、KUSANAGI 9 に移行する|無料お試しの「制限」と「最低3か月」
緩和策はあくまでつなぎです。根本的には、修正が来る環境に載せ替えるしかありません。
幸い、さくらのVPSにはKUSANAGI 9のOSイメージが用意されています。サーバー作成時にKUSANAGIを選ぶと、AlmaLinux 9かCentOS Stream 9が選べます。AlmaLinux 9はサポートが2032年までなので、迷わずこちらです。プランは1Gにしました。旧サーバーは512MBプランで動いていたので、1Gでも余裕があります。
ここで、さくらのVPSの「2週間無料お試し」について調べ直しました。以前に「無料だけど何か制限があったはず」という記憶があったからです。公式の案内を読み直した結果がこれです。
- クレジットカード払いを選んだ場合のみ、全プランが2週間無料。同時に2台まで
- お試し期間中の制限は3つ。外向きの25番ポートが閉じている(メール送信不可)、外向きの帯域が10Mbps、さくらの無償ネームサーバーが使えない
- 期間中に会員メニューからキャンセルしなければ、自動的に本登録になる
- 本登録後の最低利用期間は3か月
記憶にあった「制限」は、無償ネームサーバーの件でした。このブログはDNSをRoute 53で管理しているので影響はありません。帯域の10Mbpsも、動作確認の段階なら気になりません。
気をつけるべきは最低利用期間でした。無料期間が終わって本登録になった時点で、3か月分は確定します。1Gプランなら2,640円です。移行が終われば旧サーバーを解約するので差し引きはほぼ変わりませんが、「2週間無料だから気軽に」と思っていると、ここで少し認識がずれます。
なので、契約はすぐにはしませんでした。無料期間は作成した日から数えるので、「2週間のうちに移行とDNS切り替えまで終えられる」見込みが立ってから作る方が無駄がない、という判断です。緩和策を入れた状態で時間を稼ぎつつ移行の手順を固めて、実際にサーバーを作ったのは緩和策から4日後でした。
移行で一番気にしていたのは、PHPのバージョンよりもテーマです。このブログのSTORKは2017年のバージョンで、PHP 7.4向けに書かれています。PHP 8.3で動くのか、動いたとして警告だらけにならないか。新サーバーで動作確認してからDNSを切り替える手順にするのは、ここが理由です。
移行の手順と、STORKがどうなったかは、次の記事に書きました。
Claude Code とやった感想|調べる・判断する・手順を書く、の分担
今回の対応は、ほぼ全部Claude Codeと一緒にやりました。脆弱性の情報収集、自分のサーバーの状況整理、緩和策の選定、設定変更のコマンド作成、確認。コマンドをサーバーで打つのは自分ですが、「何を打つか」はエージェントが出してきたものを確認しながら進めています。
やってみて良かった点と、手間だった点をまとめておきます。
良かった点|調べる時間が圧倒的に短い
一番大きいのは、調べる時間です。エージェントがネット上の一次情報をごそっと取ってきて、その中から必要なものだけをまとめてくれます。今回で言えば、2件のCVEの中身、修正版のバージョン、KUSANAGIと各レンタルサーバーの対応状況、公式が出している緩和策。自分で1つずつ探していたら半日かかる量が、数分で手元に揃いました。
もう1つは、対応方針が一気に出てくることです。現役のエンジニアと言っても、人間なので、それぞれの対応の記述や設定ファイルの場所、設定値を全部覚えているわけではありません。「php.iniのどこを、どの値に」「nginxでどう書くか」が、確認の手順まで含めてまとめて提示されるのは助かります。
さらに、自分では見落としていたことが対応方針に含まれていたりします。session.upload_progress.enabled は ini_set() では間に合わない、という注意点は、自分で公式アドバイザリを読んでいたら飛ばしていたかもしれません。
手間だった点|裏取りは結局自分でやる
困った、というほどではないんですが、手間ではあるのが裏取りです。エージェントの回答が間違っていることは当然あります。なので、出てきた内容を鵜呑みにせず、自分でも一次情報を確認する必要があります。実際、さくらのVPSの無料お試しについて最初に出てきた説明は、最低利用期間の件が抜けていました。
それから、これはどうしようもないことですが、自分の環境や運用方針といったドメインレベルの知識は、当然ながら自分の方が持っています。なので、全部をエージェントの推奨どおりに進めることはできません。対応として推奨の方式が正しい場合でも、それが自分の環境や方針に合っていなければ、別の案を出してもらう必要があります。今回だと、nginxの設定でContact Form 7が止まる判断や、契約のタイミングを後ろにずらした判断は、エージェントの提案をそのまま飲まずに自分で決めています。
副産物|一人でやるより知識が増える
これは狙っていなかった効果ですが、裏取りや疑問に思ったことをその場で聞いて確認できるので、自分一人で作業しているよりも知識が増えます。「この診断結果はチャットに貼っても大丈夫か」「診断に出た17件のうち、サーバー側で本当に意味があるのはどれか」みたいな、一人なら調べずに流していたことを、作業の流れの中で確認できました。
まとめると、「調べる」と「手順を書く」はエージェント、「判断する」と「実行する」は自分、という分担です。この分担が自然に決まったのは、今回が初めてではなく、iOSアプリをClaude Codeに任せて作った経験があったからだと思います。
まとめ|「動いているから」は対策ではない
今回の件を3つにまとめます。
- EOLの環境は、脆弱性が出た瞬間に詰む。 「サポート切れ」と「脆弱性あり」は別だと思っていましたが、修正が来ない以上、脆弱性が出た時点で選択肢がなくなります。AIエージェントの時代は、その「出た時点」が以前よりはるかに早く来ます。
- 更新できないなら、攻撃面を減らして時間を稼ぐ。 公式アドバイザリの緩和策をそのまま当てるだけで、15分で確認済みの攻撃経路は塞げました。あくまでつなぎですが、何もしないのとは違います。
- ダッシュボードの警告は、読む。 「PHP の更新を推奨」は、ずっと出ていました。推奨という言葉の弱さに甘えていたのは自分です。
同じようにVPSでWordPressを動かしている方は、まず php -v と cat /etc/os-release を打ってみてください。修正版が来る環境なら、更新するだけで終わります。来ない環境なら、この記事の緩和策と移行の判断が参考になると思います。
続きは半日でPHP7.4から8.3へ|CentOS 7のKUSANAGIブログをAlmaLinux 9へです。2017年のSTORKがPHP 8.3で動いたのかどうかも、そこで書いています。






