PHP 漏洞 2026:PHP2Shell 是怎麼來的?一天升級完一批老主機的實錄與 7 項預防設定
PHP2Shell 是 2026 年 10 月 21 日修補的兩個 CVSS 9.2 未登入遠端執行漏洞,PHP 5.4 到 8.5.11 都受影響。本文拆解成因,記錄作者花九到十小時把含 Ubuntu 20.04、PHP 7.4 的老主機全部升到 8.2 以上,並整理緩解設定、Cloudflare WAF 與 7 項預防清單。
2026 年 10 月 21 日台灣時間晚上十點,PHP 官方釋出 8.5.12、8.4.27、8.3.36 與 8.2.35,修補兩個被統稱為 PHP2Shell 的漏洞。這不是一般的安全更新:只要你的主機在對外服務 PHP 網頁,不管是 WordPress、Drupal、Laravel 還是自己寫的程式,攻擊者不需要帳號密碼,一個精心構造的 HTTP 請求就可能在應用程式碼執行之前拿到伺服器的執行權。隔天資安署也發了新聞稿要求政府機關、學校與企業儘速更新。
我那天晚上把手上一批主機全部升級了一遍,花了九到十個小時。單純的 apt upgrade 其實幾分鐘就結束,真正吃時間的是幾台跑 Ubuntu 20.04、22.04 與 PHP 7.4、8.0 的老機器,還有舊版 WordPress 外掛沒有新授權這類與漏洞本身無關、卻擋在升級路上的事。這篇文章先把漏洞成因講清楚,再記錄那一晚的處理過程,最後整理一份平常就該做好的設定清單,讓下一次不必再花一整天。
技術細節查證自 php.net 的安全公告、php-src 的兩份 GitHub 安全通報、Wiz Research 的技術分析與 PHP Foundation 的事後說明,查核日期為 2026 年 10 月 22 日。漏洞成因是文件分析,不是我自己讀原始碼得出的;升級過程是第一手經驗。
PHP2Shell 是怎麼來的:兩個藏了十多年的記憶體處理缺陷
PHP2Shell 不是某個函式寫錯,而是 PHP 核心處理「記憶體不足」與「請求之間的全域狀態」兩件基礎工作的方式,各有一個長年沒被發現的缺陷。Wiz 的分析指出,過去十年內釋出的每一個 PHP 版本至少受其中一個影響;Google Cloud 的公告把受影響範圍寫成 PHP 5.4 到 8.5.11。兩個漏洞的 CVSS v4.0 評分都是 9.2,社群外洩時流傳的 10.0 是錯的。
為什麼「記憶體不足」會變成遠端執行程式碼
第一個漏洞 CVE-2026-109618 的根源是 PHP 用 longjmp() 處理記憶體不足。當某次記憶體配置失敗,PHP 會直接跳出目前的執行脈絡、中止這個請求。問題在於有些請求資料在完全初始化之前就已經可以被觸及,配置一失敗,這些資料就停在「只初始化一半」的狀態,而後續的 request shutdown 會把它們當成有效資料來讀取與判斷。
攻擊者要做的,就是讓 PHP 在剛好的時間點用完記憶體。GitHub 安全通報列出的觸發路徑都在 multipart 表單解析:缺少 content-length 處理、每個 part 的標頭數量沒有上限、空的檔案欄位搭配巢狀欄位名稱。Wiz 進一步說明,PHP 在 request startup 階段就解析 multipart 上傳,這時正常的模組初始化還沒跑完,所以 session 的 ID 與反序列化的記錄狀態特別容易被留在半成品狀態。這也是為什麼官方公告說攻擊可以在任何應用程式碼執行之前發生,而且 Wiz 表示即使應用程式從沒呼叫 session_start() 也一樣。
修補的方式是把 OOM 的 longjmp() 拿掉,改成在下一個虛擬機安全點處理的「延遲軟性 OOM」,另外設一個更高的門檻,超過就直接用 _exit() 結束行程。
為什麼上一個請求的垃圾會害到下一個請求
第二個漏洞 CVE-2026-109619 的根源是 PHP 的 worker 行程是長期存活的,而某些全域狀態(錯誤、session、物件、擴充套件的狀態)在請求結束、記憶體被釋放之後,仍然指向那塊已經不屬於任何人的記憶體。下一個請求若在正常初始化把它重設之前就讀到它,就是一次 use-after-free。
通報把這種攻擊拆成兩步:先用一個「生產者」請求留下殘留狀態(任何 fatal error 都行,包括記憶體不足與執行逾時),再讓同一個 worker 處理的下一個「消費者」請求在初始化之前用到它。已確認的消費者有兩個:一是 Apache mod_php 用目錄層級設定時,在請求初始化之前就會產生的 INI 診斷訊息(例如某個已棄用或無效的設定);二是 session upload progress,它在一般 session 初始化之前執行。被證實能做到遠端執行程式碼的最強組合,是 PHP 8.5 開啟 fatal_error_backtraces 時的 mod_php 環境。
圖 1:同一個 worker 的兩個請求如何串成 PHP2Shell
flowchart TD
subgraph R1["請求 1:攻擊者送出大型 multipart 表單"]
direction LR
A["request startup<br/>解析 multipart"] --> B["記憶體配置失敗<br/>OOM"]
B --> C["longjmp 中斷<br/>session 與反序列化狀態<br/>只初始化一半"]
C --> D["shutdown 把半成品<br/>當有效資料<br/>CVE-2026-109618"]
end
subgraph W["同一個 worker 行程繼續存活"]
direction LR
E["全域狀態仍指向<br/>已釋放的記憶體"]
end
subgraph R2["請求 2:任何人送來的下一個請求"]
direction LR
F["初始化前先跑<br/>INI 診斷或 upload progress"] --> G["讀到殘留指標<br/>use-after-free<br/>CVE-2026-109619"]
end
R1 --> W --> R2
第一個漏洞發生在單一請求內部,第二個漏洞跨越兩個請求。兩者共用同一個前提:PHP 在正常初始化完成之前就會處理攻擊者送來的資料。
為什麼 mod_php 最危險、WordPress 不用登入就中
官方把 mod_php 列為風險最高的部署方式,因為已經有一個示範攻擊能用一個未登入的請求、在任何應用程式碼執行之前完成攻擊;PHP-FPM、FrankenPHP 與 LiteSpeed 的 LSAPI 則被評估為不同程度可受影響。Wiz 在 8 月 20 日與 21 日分別對最新版的 Drupal 與 WordPress 容器映像驗證了未登入的遠端執行程式碼,之後才在 8 月 24 日向 PHP 安全團隊回報。
這件事對大多數中小企業的意義很直接:漏洞不在你的網站程式,而在 PHP 本身。Cloudflare 在公告裡特別寫了一句,只更新網站程式或外掛並不會修到這兩個漏洞。你的 WordPress 核心與外掛再新,PHP 版本沒換,網站就還是暴露的。
| 項目 | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| 官方名稱 | RCE via OOM corruption | RCE via stale global state |
| 根本原因 | 用 longjmp() 處理記憶體不足,留下半初始化的請求資料 | worker 的全域狀態在記憶體釋放後仍被下一個請求讀到 |
| 攻擊者怎麼觸發 | 大型或畸形的 multipart 請求把記憶體用完 | 先用 fatal error 留下殘留狀態,再讓同一 worker 的下一個請求讀它 |
| 已確認可遠端執行程式碼 | Apache mod_php | PHP 8.5 開啟 fatal_error_backtraces 的 mod_php;session 路徑在 mod_php 與 FPM 都驗證過 |
| 需要登入嗎 | 不需要 | 不需要 |
| 官方緩解(不等於安全) | memory_limit=-1、降低 post_max_size、前端限制請求大小 | session.upload_progress.enabled=0、8.5 設 fatal_error_backtraces=0、pm.max_requests=1 |
| 完整解法 | 更新到 8.2.35/8.3.36/8.4.27/8.5.12 | 同左 |
我的看法:這兩個洞能活十幾年,不是因為沒人看,而是因為它們藏在「正常情況下不會發生」的錯誤處理路徑裡。PHP Foundation 的事後說明提到,一位核心開發者在 2024 年修另一個稽核問題時就看到 OOM 處理的徵兆,但修法牽涉取捨,爭論了好幾個月沒有結論。到了 2026 年 8 月,三個研究團隊在兩週內各自回報,事情才動起來。
怎麼確認你的主機有沒有中、修好了沒
只要是對外提供 PHP 網頁的主機,而且 PHP 版本在 8.2.35、8.3.36、8.4.27、8.5.12 以下,就當作有中;PHP 8.1 以下的版本官方已經不維護,更是全部受影響。確認的方法依你怎麼裝 PHP 而不同,下表是我依官方公告與 Ubuntu 安全通報整理的路徑。
| 你的環境 | 怎麼確認 | 該做什麼 |
|---|---|---|
| 自己從 php.net 或官方 Docker 映像安裝 8.2 到 8.5 | php -v 看版號是否達到修補版 | 直接更新;Docker 要重新拉映像並重建容器,執行中的容器不會自動換 |
| Ubuntu 24.04 用發行版套件 php8.3 | dpkg -l php8.3-fpm 看是否為 8.3.6-0ubuntu0.24.04.13 以上 | apt update && apt upgrade,之後重啟 php-fpm 或 Apache |
| Ubuntu 22.04 用發行版套件 php8.1 | 版號會停在 8.1.2,看 Ubuntu 的修訂號是否為 1ubuntu2.28 以上 | 標準支援內有修補,照常 apt upgrade;版號不會變成 8.2,這是正常的 |
| Ubuntu 20.04 用發行版套件 php7.4 | 修補版為 7.4.3-4ubuntu2.29+esm5,只在 Ubuntu Pro 的 ESM 通道 | 開 Ubuntu Pro 吃 ESM,或換 PPA 升到 8.2 以上,或開新機搬移 |
| 用 ondrej 等第三方 PPA | php -v 看版號 | 等 PPA 釋出修補版,釋出時間會比官方慢 |
| 主機商代管、cPanel 或 Plesk | 後台看 PHP 版本;WordPress 可從「工具、網站狀態、資訊、伺服器」看 | 向主機商確認兩個 CVE 編號的修補時間,不是只看大版號 |
有一個常見的誤判:發行版的回移修補會保留舊的上游版號。Ubuntu 22.04 修完之後 php -v 還是顯示 8.1.2,Qualys 的通報也特別提醒要看發行版自己的版本字串。如果你拿 8.1.2 去對官方的 8.2.35,會以為沒修,其實已經修了;反過來,如果主機商只回你「我們是 PHP 8.3」,那也不代表修了,8.3.36 以下都還是舊的。
PHP 8.1 以下沒有官方正式版本可升。php.net 公告寫明 8.1 與更舊的版本已不再由 PHP 專案更新,但因為這次嚴重,安全團隊額外提供了 7.4、8.0、8.1 的「最小原始碼回移」分支,給自行編譯或沒有 LTS 供應商的人用。那是原始碼,不是套件,也沒有說會持續維護。多數人的實際選擇是看發行版有沒有回移,沒有就升版本。
老主機才是真正花時間的地方:我這批 Ubuntu 20.04 與 22.04 怎麼處理
那一晚九到十個小時裡,跑 24.04 的多數主機只花了很小一部分時間,大部分時間都在三四台老機器上。它們分別是 Ubuntu 20.04 與 22.04,PHP 有 7.4 也有 8.0,每一台卡的點都不同。升完之後,我手上所有主機的 PHP 最低都是 8.2 起跳。
PHP 7.4 與 8.0 沒有正式版可升,三條路各要付什麼代價
跑 7.4 或 8.0 的機器沒有「等官方修補」這個選項,只有三條路。第一條是用發行版的套件庫:22.04 的 php8.1 在標準支援內就有修補,照常更新即可;20.04 的 php7.4 修補只在 Ubuntu Pro 的 ESM 通道,沒有 Pro 就拿不到。第二條是加 PPA 直接把 PHP 換到 8.2 以上,代價是要處理所有在新版 PHP 上壞掉的程式。第三條是開一台新主機裝最新版 Ubuntu,把整個系統搬過去。
我三條都走了。有的主機用發行版自己的套件庫更新,有的用 PPA 升版本,另外有兩台我判斷原地升級不划算,直接開新主機、裝最新版 Ubuntu,再把整個系統移植過去。原地升級一台跑了好幾年的 20.04,等於要同時處理作業系統、PHP、資料庫與每一個設定檔的版本落差,出問題時很難分辨是哪一層造成的;開新機搬移雖然看起來工程大,但每一層都是乾淨的新版,問題只會出在「搬移有沒有漏東西」這一件事上。
卡住的從來不是 apt,是舊外掛與授權
真正讓那幾台老機器花掉大半夜的,是上面的 WordPress 外掛。幾個站用的外掛是舊版,而且沒有新的授權,拿不到相容新版 PHP 的更新。PHP 一升到 8.2 以上,這些外掛就直接出錯。
我沒有重買授權。一部分外掛我自己修相容性,把在新版 PHP 上出錯的地方改掉;另一部分我把網站用到那個外掛的功能重新做掉,直接拿掉對它的依賴。這個決定的邏輯是:授權過期的外掛就算這次買回來,下次 PHP 再升版還是會再卡一次,而它提供的功能其實不難自己實作。拿掉依賴之後,這些站少了一個未來會再出事的點。
這也是為什麼我在新創技術債的評估文章裡一直強調,跑在 EOL 版本上的主機要算進技術債清單。它們平常不會壞,只會在你最沒時間的那個晚上一起要債。
更新日當天,連套件來源都塞車
公告時間是台灣時間晚上十點,但那個時間點 Ubuntu 官方 mirror 上還不是最新版本,我等了大約二三十分鐘,套件才 release 到最新版。官方 mirror 之後塞了一陣子,不過很快就恢復,直接重試就好。
PPA 那邊就慢得多。它不只是連線 timeout,連修補版本的釋出時間都比 Ubuntu 官方慢很多。我最後寫了一個迴圈不斷重試,才把更新抓完整。這是我第一次遇到更新來源本身被擠爆的狀況,應該是全世界的人在同一個小時裡擠進去更新自己的伺服器。這次之後我把「套件來源有備援、更新指令要能重試」加進了平常的清單,後面會講。
一個人一天升級完的方法:AI 做了什麼、哪裡還是得靠你懂架構
這批主機如果照我以前的做法,估計要兩天;這次有 AI 幫忙,實際壓到兩三個小時就處理掉了。剩下的時間花在等套件釋出、修外掛相容性與驗證,那些是 AI 加速不了的部分。這一節講 AI 真正省到時間的地方,也講它給錯方向的地方。
AI 真的省時間的環節
省最多的是整機系統搬移。那兩台開新機的主機,要把舊機器上的服務、設定、資料與排程一樣一樣搬到新版 Ubuntu 上,以前這是最耗神的工作,因為每一個細節都要查、每一個版本差異都要對。這次我把舊機器的狀態交給 AI 盤點,讓它產出搬移步驟與對應的新版設定,我負責判斷與驗證。
第二個是把所有 config 檔做一次總整理。好幾年累積下來,每台主機的 Nginx、PHP-FPM、系統設定都有各自的歷史痕跡;趁這次升級,我讓 AI 把它們整理成一致的版本,順手把過時的設定清掉。這件事平常根本排不進時間表,這次因為反正要全部重啟,就一起做了。
Node.js 那部分也是順手處理的。同一天 Node.js 釋出 22.23.4、24.22.1 與 26.12.1 修補十個漏洞,其中 Brotli 解壓縮器的越界寫入 CVE-2026-111497 可以遠端執行程式碼。我把手上的 Node.js 從 22 升到 24,過程中有一些小問題,AI 都處理掉了,服務重啟後也做了測試。
AI 給錯方向、靠架構知識擋下來的地方
AI 不是每一步都對。這次它在 Cloudflare 的設定與某些技術選型上提出的做法,是比較不好的選擇,我直接給它正確的處理方向,它就照著做下去了。細節不展開,重點是這個模式:AI 把「查資料、寫指令、對版本差異」這些工作的速度拉得很快,但「這台機器該原地升還是搬」「這個外掛該修還是拿掉」「這條 WAF 規則會不會擋到正常功能」這些判斷,仍然要靠你對整個系統架構的理解。
我的看法:AI 讓一個人可以管理的主機數量明顯變多,但前提是這個人本來就看得懂每一層在做什麼。如果你不知道 mod_php 與 PHP-FPM 的差別,AI 建議你改哪個設定你都只能照做,出錯了也不知道從哪裡找。這跟我在從工程師到 CTO 的思維文章裡講的一樣:工具越強,判斷力越值錢。
如果你手上也有一批版本參差的主機,不確定該怎麼排優先順序,我提供架構盤點與升級規劃的顧問服務,可以先把現況攤開來看。
來不及更新時的緩解設定,以及 Cloudflare WAF 能擋到哪
官方說得很清楚:只有更新才是完整的解法,以下設定只能降低特定攻擊路徑的曝險,不會讓一台未修補的主機變安全。CISA 的建議更直接,無法立刻修補的系統應該先下線。如果你因為相容性或主機商排程真的要等幾天,至少把這些設定做了。
php.net 公告列出的緩解設定如下,要用 php.ini、FPM pool 或 Apache 的 php_admin_value 這類應用程式改不掉的方式設定,不能靠 ini_set() 或 .user.ini,而且改完要重啟每一個 worker:
; 針對 CVE-2026-109618(記憶體不足路徑)
memory_limit = -1
post_max_size = 8M ; 需要上傳檔案的站用 32M
upload_max_filesize = 2M ; 必須小於 post_max_size
; 針對 CVE-2026-109619(跨請求殘留狀態)
session.upload_progress.enabled = 0
; 只有 PHP 8.5 需要
fatal_error_backtraces = 0
幾個要注意的地方。memory_limit=-1 看起來違反直覺,它的用意是不讓 PHP 自己觸發那個有問題的記憶體不足處理路徑,改用容器或 cgroup 的記憶體上限當可用性的邊界;但 GitHub 通報也說這招不完整,因為 mmap() 失敗時還是會走到同一條路。官方明確叫你不要用 RLIMIT_AS 或 RLIMIT_DATA 來限制記憶體,因為那正好會製造出漏洞需要的配置失敗。對 PHP-FPM 來說,把 pm.max_requests 設成 1 可以讓每個請求都用全新的 worker,殘留狀態就無處可留,代價是效能。
關掉 session upload progress 是這次我覺得值得特別講的一項。它預設是開的,不需要應用程式呼叫 session_start() 就會進入相關流程,所以多數人不知道自己有在用它。我的判斷是它只是修補前的過渡措施,更新完就不必再關;GitHub 通報則建議如果你的應用用不到這個功能,修補後也可以保持關閉。兩種做法都成立,差別在你要不要多維護一個非預設的設定。
Cloudflare WAF 擋到哪裡
Cloudflare 在 10 月 21 日 UTC 凌晨三點就部署了針對 PHP2Shell 的受管規則,比公開揭露早了大約九小時,而且所有有 WAF 的方案都自動啟用,包括免費方案。付費方案要自己確認 Managed Ruleset 是在 block 模式而不是只記錄。這套規則用了 Cloudflare 新的「完整交易偵測」能力,同時看請求與伺服器回應,可以在外洩的資料回到攻擊者手上之前把回應擋掉。
但 Cloudflare 自己也說了兩件事:一是他們已經觀察到攻擊者在修改攻擊 payload 試圖繞過規則;二是有 WAF 也還是要更新 PHP。WAF 是多一層保護,不是修補。
我自己這次在 Cloudflare 上做的是加 IP 限制,以及把沒有用到上傳功能的站直接擋掉 multipart 請求,這與 GitHub 通報的建議一致。Bot Fight Mode 本來就開著。改完之後沒有任何網站因為規則太嚴格而擋到正常功能,這一點要歸功於規則是依每個站的實際用途設的,不是一套規則套所有站。
平常就該做好的 7 項預防設定
這七項是我這次之後整理出來的清單,全部都該做,比較保險。它們的共同目標是讓下一次零時差漏洞來的時候,你只需要跑更新與驗證,不需要同時處理版本落差、授權、設定不一致與更新來源塞車。
| # | 設定 | 為什麼 | 這次有沒有救到我 |
|---|---|---|---|
| 1 | 追蹤每台主機的 EOL 日期 | PHP 8.2 在 2026 年 12 月 31 日就 EOL;Ubuntu 20.04 的修補要 Ubuntu Pro。EOL 的版本在零時差漏洞來時沒有官方修補可等 | 沒有,那幾台老機器就是沒追才會留到這天 |
| 2 | 開啟自動安全更新,只套安全性更新 | 作業系統層的安全更新大多可以無人值守套用;應用層的大版本升級另外排 | 部分,24.04 那批很快就處理完 |
| 3 | mod_php 換成 PHP-FPM | 官方把 mod_php 列為這次風險最高的部署方式;FPM 的 worker 可以設 pm.max_requests,隔離也比較好 | 有,我的站都是 FPM |
| 4 | WAF 常開且確認在 block 模式 | Cloudflare 的規則比公開揭露早九小時上線;免費方案也有,但付費方案要自己確認不是只記錄 | 有,爭取到更新的時間 |
| 5 | 更新前先快照或備份 | 升級 PHP 版本會讓舊程式出錯,要能立刻退回 | 有,兩台搬移的主機因此敢放手做 |
| 6 | 監看 PHP worker 的子程序 | CISA 與多家廠商都建議監看 php-fpm、apache2 有沒有啟動 shell、下載工具或偵察指令,那是被打進來的最直接訊號 | 這次是新加的 |
| 7 | 套件來源有備援、更新指令能重試 | 更新日當天 Ubuntu 官方 mirror 慢了二三十分鐘才釋出,PPA 更慢且反覆 timeout | 沒有,那天是臨時寫迴圈撐過去的 |
第 1 項是最便宜也最常被跳過的。一張表記下每台主機的作業系統版本、PHP 版本、各自的 EOL 日期,每季看一次,就能把「升級」從緊急事件變成排程事項。這次把老機器拖到最後一刻的代價,就是在全世界都在搶更新的那個晚上,同時處理四層的版本落差。
第 7 項是這次的新體悟。過去我沒有把「更新來源會塞車」當成風險,因為沒遇過;但 AI 讓漏洞的發現與武器化都變快之後,零時差大規模修補日會越來越常見,而大家會在同一個小時裡擠進同一批 mirror。更新腳本要能判斷是來源還沒釋出還是自己的網路問題,並且能自動重試,不然你只是坐在那裡盯著 timeout。
為什麼今年起更新要跟得更緊:AI 在兩邊都加速
PHP2Shell 之所以值得當成一個轉折點來看,是因為它同時展示了 AI 在攻與守兩邊的加速。找到這兩個漏洞的 Wiz 團隊在公告裡寫明,他們用了多個模型,其中 Gemini 4 Argon 對發現漏洞、開發攻擊程式、偵測攻擊與驗證修補都有重大貢獻,模型也協助他們把攻擊程式適配到不同的 PHP 版本、設定與記憶體佈局。同一天 Node.js 修補的 Brotli 遠端執行漏洞,回報者是 OpenAI Codex Security 的研究員。
PHP Foundation 的事後說明給了一個更宏觀的數字:從 2026 年 7 月 1 日起,他們已經發布 15 個 CVE,另外有超過 100 份回報是無效、重複或無法重現的。他們把回報量的上升與 AI 輔助的安全研究連在一起,也提到此前有 Claude Mythos 與 Alpha-Omega 合作對 PHP 做過掃描。這些藏在錯誤處理路徑裡十多年的缺陷,在人工稽核時代能一直活著,在模型可以系統性讀完整個程式庫的時代就很難了。
攻擊方同樣在加速。Help Net Security 轉述 Amazon 的說法,他們的蜜罐在 10 月 17 日就記錄到一次利用嘗試,那時漏洞還在禁運期內;PHP Foundation 的時間線則記錄了 10 月 20 日 CVE 編號外洩、同晚一支誤發的概念驗證影片在社群流傳、10 月 21 日凌晨一家容器映像供應商提前六小時發布含修補的映像,讓任何人都能從二進位檔反推修法。官方因此把釋出時間提前了一天。從漏洞被研究團隊發現到修補釋出,中間是兩個月的協調;從修補釋出到攻擊者拿到可用的攻擊程式,可能只剩幾小時。
我的看法:今年開始,大家都得把更新的腳步跟得很緊,稍微沒跟到最新版本就很容易出事。好消息是同一股力量也站在防守這邊:有 AI 幫忙,一個人可以管的主機數量比以前多,這次整批更新也很順利。壞消息是這不會讓「懂系統架構」變得不重要,反而更重要,因為 AI 只能在你給對方向的前提下做對的事。
這也是企業做 AI 治理時常漏掉的一塊。我在AI 治理與資安的實戰文章談的是怎麼管公司內部的 AI 使用,但 AI 對資安的另一個影響是外部的:攻擊者用它找洞的速度變快了,你的修補節奏必須跟上。同樣的,當你開始讓 AI Agent 進到公司的系統裡,那些 Agent 跑的主機也在這份更新清單上。
結論:把升級變成排程,不要變成事件
PHP2Shell 的兩個漏洞是 PHP 核心的記憶體處理缺陷,PHP 5.4 到 8.5.11 全部受影響,不需要登入就能利用,而且不是更新網站程式或外掛就能修好的。修法只有一個:把 PHP 升到 8.2.35、8.3.36、8.4.27 或 8.5.12 以上;8.1 以下要靠發行版的回移修補或直接升版本。緩解設定與 WAF 只能爭取時間。
那一晚我學到的是,升級本身從來不是問題,問題是所有被拖延的決定會在同一個晚上到期:EOL 的作業系統、沒授權的外掛、不一致的設定、沒有備援的套件來源。AI 把執行的時間壓到了原本的一小部分,但哪台該搬、哪個外掛該拿掉、哪條規則不能開,還是得由懂架構的人來決定。
如果你的公司手上也有一批沒人敢碰的老主機,或是這次更新時發現連盤點都做不出來,歡迎預約架構盤點與升級規劃的顧問諮詢,我們可以先把每台主機的版本、EOL 日期與依賴攤開,排出一份不必再熬夜的升級順序。當年我選 PHP 與 Laravel 做快速開發的理由至今沒變,但選了它就要負起跟著它的版本走的責任。
常見問題 FAQ
只更新 WordPress 核心與外掛,PHP2Shell 就修好了嗎?
沒有。PHP2Shell 的兩個漏洞在 PHP 語言本身,不在 WordPress 或任何外掛的程式碼裡,Cloudflare 的公告也明確寫了更新網站程式或外掛不會修到這兩個漏洞。你必須把伺服器上的 PHP 升到 8.2.35、8.3.36、8.4.27 或 8.5.12 以上,或是套用發行版的回移修補。可以從 WordPress 後台的「工具、網站狀態、資訊、伺服器」看目前的 PHP 版本,但要確認到小版號,只看「PHP 8.3」不夠。
有 Cloudflare WAF 擋著,可以晚幾天再更新 PHP 嗎?
不建議。Cloudflare 的規則確實比公開揭露早九小時上線,免費方案也有,但 Cloudflare 自己已經觀察到攻擊者在修改 payload 試圖繞過,而且規則只保護經過 Cloudflare 的流量,直接打到來源伺服器 IP 的請求擋不到。WAF 的價值是替你爭取排程更新的時間,不是替代更新。付費方案還要自己確認 Managed Ruleset 是 block 模式而不是只記錄。
PHP 7.4 現在到底還能不能用?
PHP 7.4 在 PHP 官方已經停止維護,這次沒有正式修補版本,只有一個給自行編譯者用的最小原始碼回移分支。如果你用 Ubuntu 20.04 的 php7.4 套件,Ubuntu 有提供修補,但只在 Ubuntu Pro 的 ESM 通道。沒有 Pro 又不能自己編譯的話,實際可行的選擇是升到 8.2 以上,並處理升級後壞掉的程式。我自己這次是把所有 7.4 與 8.0 的主機全部升到 8.2 以上,有兩台直接開新主機搬移。
主機商說「已修補」,但 php -v 的版號沒變,怎麼確認真的修了?
看發行版自己的修訂號,不是上游版號。Ubuntu 22.04 修補後 php -v 仍然顯示 8.1.2,要用 dpkg -l 看套件版本是否為 8.1.2-1ubuntu2.28 以上;Ubuntu 24.04 的 php8.3 要看是否為 8.3.6-0ubuntu0.24.04.13 以上;Ubuntu 20.04 的 php7.4 是 7.4.3-4ubuntu2.29+esm5。向主機商確認時,直接問他們針對 CVE-2026-109618 與 CVE-2026-109619 套用的套件版本與時間,以及所有 PHP worker 是否都已經重啟。
memory_limit=-1 不會讓主機被打到當機嗎?
會有這個風險,所以官方要你搭配容器或 cgroup 的記憶體上限一起用,讓作業系統層而不是 PHP 自己來處理記憶體用盡。這個設定的目的是避開 PHP 內部有漏洞的記憶體不足處理路徑,把「記憶體用完」從可被利用的程式碼執行變成單純的服務中斷。官方同時提醒不要用 RLIMIT_AS 或 RLIMIT_DATA,因為那會讓 mmap() 失敗,反而走回漏洞路徑。這些都是修補前的過渡措施,更新 PHP 之後就該依正常需求設回去。
分享這篇文章
