資安與漏洞

PHP2Shell 修補與實戰升級 SOP:8.2 到 8.2.35、7.4 只能自己編譯

admin · 10月22日 · 2026年 · · · · · 本文共3871个字 · 预计阅读13分钟55次已读

一句話直答:能升就升到 8.5.12、8.4.27、8.3.36 或 8.2.35(或發行版的對應套件),升完一定要重啟 PHP worker;7.4、8.0、8.1 沒有正式修補版,只能走官方 php-src 的 minimal source backports 自行編譯,或換到有維護的管道。下面是我們在寶塔面板加 nginx 的多版本環境實際走完的流程,含三個真實踩到的坑。

修補版清單與取得管道

分支 修補版 備註
PHP 8.5 8.5.12 低於此版本皆受影響;這條分支另有致命錯誤回溯相關的觸發路徑
PHP 8.4 8.4.27 低於此版本皆受影響
PHP 8.3 8.3.36 8.3.35 還沒修,別停在上一版
PHP 8.2 8.2.35 此分支 2026 年 12 月 31 日進入 EOL,不建議長期停留
PHP 8.1/8.0/7.4 無正式版 只有官方 minimal source backports,需自行編譯

發行版與控制面板各有自己的版號:Ubuntu 的 USN-8948-1 涵蓋 22.04/24.04/26.04/26.10,較舊的 20.04 及更早由 USN-8948-2 提供(多數需要 Ubuntu Pro/ESM);Debian、RHEL、cPanel 的 EasyApache(含 ea-php7.4/8.0/8.1 的修補版)也都陸續跟進。判斷原則只有一條:以你實際安裝的那個套件版號與它的公告為準。

PHP2Shell 修補與實戰升級 SOP:8.2 到 8.2.35、7.4 只能自己編譯

先決定路線,再動手

  1. 用發行版套件(apt/dnf):apt update && apt install --only-upgrade 目標套件,然後重啟服務。別忘了:沒有先 apt-get update,你會停在還沒修的上一版,這是當天很多人踩到的第一個坑。
  2. 面板或自建多版本環境:寶塔、cPanel、EasyApache、Docker 映像。每個 PHP 版本要各自處理,面板的編譯式升級會重編,請排離峰時段。
  3. EOL 但短期搬不動:用官方回移植分支自行編譯,或改用發行版/廠商的延長支援套件。扛不住就規劃遷移到 8.3 以上。

實戰:我們的環境與做法

環境是寶塔面板加 nginx,同一台機器上多個 PHP 版本共存(7.0、7.2、7.3、7.4、8.2、8.5)。10 月 22 日完成的內容:

  • 8.2 由 8.2.31 升到 8.2.35,8.5 由 8.5.6 升到 8.5.12。
  • 7.4 沒有正式修補版,改用官方 php-src 的回移植分支自行編譯,產出 7.4.34。
  • 7.0、7.2、7.3 直接停用並移除。這三條分支連官方回移植都沒有,留著只是持續暴露,而且沒有任何站台必須綁在它們上面。
# 步驟 1:盤點,哪個站台用哪個 PHP(看 vhost 指向哪個 socket)
grep -rn "fastcgi_pass" /www/server/panel/vhost/nginx/ | grep -o "php-cgi-[0-9.]*" | sort | uniq -c

# 步驟 2:逐一確認目前版本
for v in 74 82 85; do echo -n "$v: "; /www/server/php/$v/bin/php -v 2>/dev/null | head -1; done

# 步驟 3:升級與重啟(worker 沒重啟等於沒修)
/etc/init.d/php-fpm-82 reload
ps -o lstart= -p $(pgrep -o php-fpm)

# 步驟 4:確認載入的 binary 真的換了
ls -l /proc/$(pgrep -o php-fpm)/exe

7.4 走的是官方回移植分支(分支名帶 -CVE-2026-109618-109619 後綴)。編譯流程與一般原始碼編譯相同:取得分支、依原本的 configure 參數重建、安裝到固定路徑。關鍵在於保留原本編譯時的參數與擴充清單,否則很容易編出一個「版本對、功能不對」的 PHP。

# 概念示意:用原機器的參數重建,避免擴充消失
./configure --prefix=/www/server/php/74 ...(沿用舊的參數)
make -j$(nproc)
make install
# 完成後務必比對擴充清單(見下一節的第 2 個坑)

三個實戰教訓

一、只有 HTTP 200 不算驗收

升級後某個站台照樣回 200,看起來一切正常,實際上頁面已經殘掉了:內容輸出從 39KB 掉到 5KB。狀態碼只代表「連得上」,不代表「內容對」。這種半殘狀態最危險,因為監控不會叫,訪客卻看到破頁。

# 逐站比對輸出大小
curl -s -o /tmp/home.html -w "%{http_code} %{size_download}
" https://你的網域/
# 並檢查 PHP 錯誤數有沒有突然增加
grep -c "PHP Warning\|PHP Fatal\|PHP Notice" /www/wwwlogs/php-error.log

驗收標準要寫成「輸出大小與升級前同一量級(例如相差 10% 內)」,而不是「有回 200」。

二、升級會把擴充弄掉,兩個站立刻 500

這次升級過程中 Redis 擴充沒被帶上,兩個站馬上掛掉,錯誤訊息分別是 Please make sure the PHP Redis extension is installed and enabled. 與 not support: redis。教訓是:升級前先存一份擴充清單,升級後逐一比對,不要假設面板會幫你保留。

# 升級前後各存一份,然後比對少了什麼
/www/server/php/82/bin/php -m | sort > /tmp/ext_before.txt
# ...(升級)
/www/server/php/82/bin/php -m | sort > /tmp/ext_after.txt
comm -23 /tmp/ext_before.txt /tmp/ext_after.txt

要盯的重點擴充:redis、imagick、gd、opcache、curl、mbstring、intl、swoole,以及任何你專案自己編的擴充。編譯式升級時也一併確認 php.ini 裡的 extension= 行沒被覆蓋。

三、CLI 與網頁讀不同的 ini

寶塔的 CLI 讀 php-cli.ini,網頁(FPM)讀 php.ini。只改一份會出現「明明改了卻沒生效」的假象,尤其在調整 post_max_size、memory_limit 這類過渡緩解設定時特別容易誤判。要改就兩份都改,並且用 web SAPI 實際驗證。

# 看 CLI 載入哪一份
/www/server/php/82/bin/php --ini | head -5
# 用 web SAPI 驗證(放一個臨時檔案,看完立刻刪掉)
# <?php echo ini_get('post_max_size'), ' | ', ini_get('memory_limit'); ?>

驗收清單(照著打勾)

  • php -v 與 /proc/<pid>/exe 兩者都指向修補版,且服務中的 binary 就是它。
  • PHP worker 與網頁伺服器都已重啟,進程啟動時間在升級之後。
  • 每個站台首頁回 200,且輸出大小與升級前同一量級。
  • PHP 錯誤日誌沒有新增 Fatal,也沒有殘頁造成的內容異常。
  • 擴充清單與升級前一致(redis/imagick/gd/opcache 優先)。
  • 至少觀察 24 小時的 5xx 與 CPU、記憶體變化。
  • 過渡緩解設定(阻擋 multipart、pm.max_requests=1 等)已經移除,避免和新版本互相干擾。
  • 回滾方式寫明且實測過:舊版檔案、舊 ini、舊 socket 路徑都還在。

PHP2Shell 修補與實戰升級 SOP:8.2 到 8.2.35、7.4 只能自己編譯

回滾怎麼做

升級前先做兩件事:把要動的 ini 與 vhost 設定整份備份,資料庫做一次快照。面板型環境通常可以切回舊版 PHP,但前提是舊版目錄還在、沒被覆蓋。回滾的觸發條件建議明訂:出現 Fatal 導致站台不可用、擴充補不回來、或升級後輸出內容明顯異常且 30 分鐘內找不出原因,就切回舊版並改用過渡緩解撐到問題排除。

還來不及修的過渡做法

再強調一次,這些都不是解法,只是把暴露面壓小:關閉 session.upload_progress.enabled(擋掉已知的一條路徑)、把 post_max_size 調小(無上傳需求 8M、有上傳 32M,並讓 upload_max_filesize 更低)、限制 max_input_vars 與 max_file_uploads、在邊緣或 WAF 阻擋 multipart(會影響上傳)、FPM 設 pm.max_requests = 1。多家廠商都強調這些措施無法完全阻擋利用;真的排不出時間,把服務隔離或下線會比撐著安全。

常見問題

我升級了,但 php -v 還是顯示舊版號怎麼辦?

先確認你看的是哪一個 SAPI 與哪一支 binary。CLI 與 FPM 可能是不同安裝,面板的多版本環境尤其常見。用 ls -l /proc/$(pgrep -o php-fpm)/exe 看服務中那一支,再看它的啟動時間是否已更新。

一定要重啟嗎?

要。已載入記憶體的舊程式碼不會自己變成新版,不重啟 PHP worker 或網頁伺服器,修補等於沒生效。

8.2 修好了,為什麼還建議搬走?

8.2 在 2026 年 12 月 31 日進入 EOL,之後這條分支不會再有安全更新。趁這次升級順手規劃到 8.3 或 8.4,下次漏洞來時你會少一件事要做。

接下來看這兩篇

升級本身不難,難的是驗收與善後。把上面的清單印出來貼在旁邊,一項一項打勾,就不會出現「回 200 但頁面已殘」或「擴充掉了兩個站掛掉」這種事。如果你也在多版本面板環境升級,歡迎留言補充你遇到的坑,讓後來的人省下那幾十分鐘。

0 条回应