資安與漏洞

PHP2Shell 漏洞從哪來?CVE、GHSA、USN 與上游分支怎麼追

admin · 10月22日 · 2026年 · · · · · 本文共3318个字 · 预计阅读12分钟19次已读

一句話直答:這不是某個框架或外掛的 bug,而是 PHP 核心在「發生致命錯誤時怎麼收尾」的設計缺陷,可觸發的程式碼最早可追溯到 2012 年的 PHP 5.4。要確認自己是否受影響,不能只看 php -v 開頭的數字,要看發行版套件的版號、以及真正在回答網頁請求的那個 SAPI。

上一篇談危害,這篇談追蹤。看懂編號體系之後,你在下一次重大漏洞時可以自己判斷,不必等別人餵結論。

漏洞從哪來:兩個被打破的假設

兩個 CVE 共用同一個根因:PHP 用 longjmp() 處理致命錯誤,直接拋棄執行現場,然後進入一段假設「所有資料結構都完整」的清理流程。細節分別落在兩個不同的地方:

  • CVE-2026-109618(記憶體耗盡路徑):與請求解析、multipart 處理以及 session 上傳進度(ext/session 的 upload progress 回呼)有關。研究指出其中一個前提來自 2017 年 10 月的效能優化,首次出貨於 2018 年 12 月的 PHP 7.3.0,改變了雜湊表的排列順序,讓「標記了項目但記憶體未配置」的狀態變得可被外部操控。
  • CVE-2026-109619(致命錯誤與殘留狀態路徑):致命錯誤回溯(fatal error backtrace)與跨請求的模組級全域狀態。相關的序列化與 session 程式路徑可以再往前追到 PHP 7.1 與 PHP 5.4。官方公告記錄了一條已驗證的 PHP-FPM 利用路徑。

另外值得記一筆的是發現方式:多家媒體報導這兩個漏洞是在 AI 協助下找出來的,評級 CWE-824、CVSS v4.0 9.2。它提醒我們一件事,長年潛伏的記憶體問題不會因為「大家用了十年沒事」就自動變安全。

同一件事,四種編號:各自代表誰在負責

新手最常卡住的不是技術,是「這麼多號碼到底哪個算數」。答案是:它們負責的交付鏈不同。

體系 誰發布 回答什麼問題 這次的值
CVE MITRE/CVE.org 全球統一的漏洞身分證,跨廠商對照用 CVE-2026-109618、CVE-2026-109619
GHSA GitHub Advisory(PHP 專案在 php/php-src 的 security advisories 發布) 上游開發者自己怎麼描述、影響範圍與修補提交 GHSA-w8hw-w9fx-j79w、GHSA-6wmf-4rv5-p3rp
USN/DSA/DLA/RHSA Ubuntu/Debian/Red Hat 等發行版 「你機器上裝的那個套件」什麼版本才是修好的 USN-8948-1、USN-8948-2 等
上游 release 與分支 PHP 專案(php.net 與 php-src) 原始碼層級的修補點,以及沒有正式版的分支怎麼辦 8.5.12/8.4.27/8.3.36/8.2.35

PHP2Shell 漏洞從哪來?CVE、GHSA、USN 與上游分支怎麼追

為什麼要有四層?因為從原始碼到你的機器之間至少有兩層轉手:上游給你原始碼,發行版或控制面板(cPanel、寶塔、Docker 映像)給你實際安裝的東西,你的服務商再幫你決定能不能更新。任何一層沒動,漏洞就還在。所以專業的追蹤習慣是「用 CVE 編號橫向對照每一層」,而不是只讀一則新聞。

怎麼自己判斷手上版本是否受影響

  1. 列出所有 PHP 執行環境,先確認哪一個在服務網站。CLI 的版本往往和 php-fpm 不同,這是誤判的最大來源。
  2. 對照修補版清單:8.5 需 8.5.12、8.4 需 8.4.27、8.3 需 8.3.36、8.2 需 8.2.35;低於這些數字就受影響。8.1、8.0、7.4 及更舊沒有正式修補版。
  3. 看發行版套件版號,不要套上游版號。Ubuntu 的修補是以套件形式進到既有版本號裡,同一台機器上「看起來很舊」的版號其實已修好。
  4. 確認修補後的二進位真的被載入,且 worker 已重啟。換了檔案卻沒重啟 PHP-FPM 或網頁伺服器,等於沒修。
# 一、列出所有已安裝的 PHP 套件與版本(Debian/Ubuntu)
dpkg -l 'php*' | awk '/^ii/{print $2, $3}'
apt list '?installed ?name(^php[0-9.]+$)'      # Ubuntu 官方建議的寫法

# 二、RHEL 系
rpm -qa 'php*' | sort -V | tail -20

# 三、正在服務的執行檔與啟動時間(重啟過才會有新的時間)
ls -l /proc/$(pgrep -o php-fpm)/exe
ps -o lstart= -p $(pgrep -o php-fpm)

# 四、哪個 ini 真的被載入、關鍵設定目前是什麼
php --ini | head -5
php -r 'echo "upload_progress=", ini_get("session.upload_progress.enabled"), " post_max_size=", ini_get("post_max_size"), PHP_EOL;'

PHP2Shell 漏洞從哪來?CVE、GHSA、USN 與上游分支怎麼追

關於第三步的陷阱,具體一點說:Ubuntu 24.04 的 php8.3 修補版版號是 8.3.6-0ubuntu0.24.04.13,22.04 的 php8.1 是 8.1.2-1ubuntu2.28。如果你拿「8.3.36」去 grep,會得出「還沒修」的錯誤結論;反過來,如果在更新的機器上只看 php -v 前三個數字,也可能誤以為自己修好了。正確做法是打開發行版的公告頁,或查套件的 changelog。

EOL 分支:7.4/8.0/8.1 的「官方分支」是什麼意思

PHP 專案已不為這些分支發布正式版本,這次因為嚴重程度例外提供了 minimal source backports,分支名稱帶有 -CVE-2026-109618-109619 後綴(例如 PHP-7.4-CVE-2026-109618-109619)。重點在於:

  • 它只對自行編譯的人有用,不會變成一般套件更新,也不代表這些分支恢復常規支援。
  • 它的定位是「給沒有維護廠商、又必須先撐住的人一條路」,不是長期方案。
  • 分支上的版本號可能顯示為開發版(例如 7.4 分支在編譯時顯示為 7.4.34-dev 這類字樣),別拿它去跟正式版號硬比。

除了官方回移植,還有幾條路:發行版的延長支援(Ubuntu 20.04 的 php7.4 修補在 USN-8948-2,需要 Ubuntu Pro/ESM)、Debian 的付費 ELTS、RHEL 是否回移植要逐一套件確認、控制面板(cPanel 的 EasyApache 有 ea-php7.4/8.0/8.1 的修補版)、以及社群自行編譯的 Docker 映像。最後一種要特別小心:社群映像方便,但沒有經過 PHP 專案審核,用之前請確認它的 patch 來源與版本一致性。

五個查證習慣

  • 三方交叉:上游 release 公告、php-src 的 GHSA、你的發行版 USN/DSA,三個都看過再下結論。
  • 用編號去找,不要用新聞去找:把 CVE 編號丟進發行版的漏洞追蹤頁,比讀十篇轉貼快。
  • 看誰簽名:官方公告、發行版公告、廠商部落格的可信度不同,轉貼文只當線索。
  • 記錄查詢日期與來源網址:漏洞資訊一週內會更新好幾版(修補版號、影響範圍、緩解有效性都可能改)。
  • 把結論寫進資產清單:哪台機器、哪個版本、什麼時候升、誰驗收。三個月後你會感謝現在的自己。

常見問題

我只要記住「升到 8.3.36 就好」嗎?

上游層面可以這樣記,但實務上不夠。你要記的是「我的交付管道把修補送到了哪個版號」,因為套件、面板與 Docker 映像各有自己的版號規則。

沒有正式修補版的 7.4,還有人提供修補嗎?

有,來源分三類:PHP 專案自己的原始碼回移植分支、發行版或廠商的延長支援(多為付費),以及社群自行編譯的映像。前兩類可以查 patch 與公告,第三類要自己驗證。

我看的是 CLI 版本,這樣夠嗎?

不夠。網站跑的是 FPM 或 mod_php,兩者的設定與 binary 可能不同。至少要看一次 /proc/<pid>/exe 指向哪一支執行檔。

接下來看這兩篇

把上面的四步檢查跑完,你手上就會有一張「機器對應 PHP 版本」的表,那張表在下次漏洞來臨時可以直接重複使用。如果追蹤過程中遇到版號看起來很舊、但其實已經修好的情況,歡迎留言貼出來,讓其他人少踩一次同樣的坑。

0 条回应