AIREITER

OpenAI Codex PHP2Shell Checker 指南:正確解讀 UNKNOWN

最近更新: 2026-10-22 09:16:12

OpenAI 的 php2shell-checker 適合拿來做第一輪檢查,但不能單靠它證明伺服器安全。它會將 HTTP 標頭或 php -v 顯示的 PHP 版本,與內建的修補版本門檻進行比對。因此,隱藏版本標頭可能導致結果為 UNKNOWN;另一方面,Linux 發行版若以 backport 方式套用修補,也可能讓已修好的伺服器看起來仍然容易受攻擊。

OpenAI php2shell-checker GitHub 儲存庫

先看懂四種結果

OpenAI 官方儲存庫會回報三種主要狀態。請把它們視為初步分流訊號,而不是完整的漏洞評估結果。

輸出結果結束代碼代表什麼下一步
OK0已辨識的分支版本達到或高於最低修正版確認實際提供網頁流量的 PHP 程序使用的就是這個版本
VULNERABLE1偵測到的版本低於最低修正版更新提供服務的 runtime、重新啟動 workers,再重新執行兩種檢查
UNKNOWN3檢查器無法確認可辨識的版本或回應改在伺服器本機檢查;不要把它當成已完成修補
參數無效2指令本身不符合格式修正指令後重新執行
PHP2Shell checker 結果代碼

OpenAI 提供了哪些工具

公開的 php2shell-checker 儲存庫包含 Node.js 指令稿、測試,以及兩個 Codex skills:phpcheck-url 用來檢查可連線的網站,phpcheck-server 則適用於你能登入的伺服器。它的工作是整理版本證據,不會利用漏洞攻擊目標,也不會掃描應用程式程式碼。

依照情境選對檢查方式

檢查公開 URL

先 clone 或下載儲存庫,再用 Node.js 指令稿檢查網站:

node phpcheck.js "https://example.com"

遠端檢查會先送出 HTTP HEAD 請求,只有伺服器回傳 405 或 501 時才改用 GET。它會讀取 X-Powered-By 和 Server,不會跟隨重新導向,也不會檢查回應本文。

CDN、反向代理、expose_php=off 或自訂伺服器設定,都可能在回應送到檢查器前移除 PHP 版本。若結果是 VULNERABLE,就需要進行修補;若只是沒有版本標頭,則應改取得伺服器本機證據。

檢查本機 PHP binary

在已安裝 PHP 的機器上執行:

node phpcheck.js --local

這會對目前 PATH 中可用的 binary 執行 php -v。但它無法證明網站使用的就是同一個 binary:同一台主機可能同時存在獨立的 CLI、PHP-FPM、CGI、Apache module、container,或從原始碼編譯的多套安裝。

完成本機檢查後,還要找出實際連接網頁伺服器的 runtime。若是 container 部署,請檢查正在執行的 container,不要只看 image tag。若是套件管理的服務,則應確認相關的 PHP-FPM pool 或 Apache module,並查看供應商的套件變更紀錄。

安裝並使用 Codex skills

官方 README 提供了一個 Codex 指令,可以一次安裝兩個 skills:

$skill-installer install both skills from https://github.com/openai/php2shell-checker

接著依照你的存取權限選擇合適的介面:

$phpcheck-url check https://example.com
$phpcheck-server check the PHP version serving my site

Codex 並非必要。對 CI 工作或資源精簡的主機來說,Node.js 指令仍是最直接的介面。若要自動化,請加上 --json;其中的 patch_status 欄位會回傳 ok、vulnerable 或 unknown,不必另外撰寫腳本解析終端機上的文字。

驗證下載的 checker

這個儲存庫使用 Node 內建的測試 runner:

node --test phpcheck.test.js

測試套件會透過本機 HTTP 伺服器測試 CLI,也會在本機情境使用假的 PHP executable。README 表示,它不需要實際安裝 PHP,也不需要連線到外部網站。

把 UNKNOWN 當成除錯結果

請把 UNKNOWN 視為證據不足。目標可能隱藏 PHP 版本、使用尚未辨識的分支、沒有正常回應,或執行較新的 prerelease;這些情況都不能證明修補已經存在。

真實使用者 @jvr0x 用這句話概括了限制:

「它其實只是拿版本跟 10 月 20 日的門檻比對,所以隱藏標頭最後會得到 UNKNOWN。」

遠端指令看到的是 HTTP 回應,而不是反向代理後方的程序。既然版本標頭被隱藏,就應該改做伺服器端檢查,而不是反覆測試 URL。

遇到 UNKNOWN 後,可以依序進行:

  1. 在提供網站服務的主機上執行 node phpcheck.js --local。
  2. 確認請求實際到達的是 PHP-FPM、CGI、Apache mod_php,還是 container。
  3. 查看供應商套件的變更紀錄,確認是否有 backport 修補。
  4. 更新後重新啟動相關的 PHP-FPM 或 Apache workers。
  5. 透過實際提供服務的路徑驗證,不要只檢查 shell 預設的 php binary。

如果沒有 SSH,URL 模式可能就是唯一能做的第一輪檢查。若共用主機隱藏了版本標頭,就需要請託管供應商確認實際提供服務的 runtime、套件修訂版本,以及 workers 是否已重新啟動。

版本表不能單獨決定是否完成修補

這個 checker 將 PHP 8.5.12、8.4.27、8.3.36 和 8.2.35 視為各分支的最低上游修正版。官方測試也確認 8.4.26 會被判定為 VULNERABLE,8.4.27 則是 OK;PHP 官方將 8.5.12、8.4.27、8.3.36 和 8.2.35 列為安全性版本。

分支最低上游修正版上一個被判定為有漏洞的版本
PHP 8.58.5.128.5.11
PHP 8.48.4.278.4.26
PHP 8.38.3.368.3.35
PHP 8.28.2.358.2.34
部署情境為什麼單純比對版本可能誤導應採用的證據
隱藏 X-Powered-By 或 Server 標頭遠端 checker 無法辨識 PHP本機 runtime 清單
Debian 或 Ubuntu 安全性套件供應商可能在較舊的上游版本字串下 backport 修補供應商公告與套件變更紀錄
同一台主機上的 PHP-FPM 與 CLIphp -v 顯示的可能是 CLI,而不是 HTTP worker網頁伺服器與 FPM 設定
快取的 container 或固定的 digestregistry tag 可能已更新,但正在執行的 container 仍是舊版本執行中 container 的 image ID 與版本
Apache 或 FPM workers 未重新啟動修正版檔案雖已寫入磁碟,舊 workers 仍可能持續運作程序啟動時間與重新啟動後的檢查結果
不支援的分支或 prereleasechecker 可能無法辨識供應商特有的修補狀態PHP 或供應商的安全性公告

儲存庫的限制說明指出,這項工具假設列出的分支在較新的穩定版本中包含修補,且無法獨立驗證修補是否真的存在。發行版可以在不更改上游版本號的情況下套用安全性 backport,因此,與其只看顯示的版本號,供應商的變更紀錄通常更具說服力。

更新 WordPress、Drupal、Laravel 或其他 PHP 應用程式,不等於修補 PHP engine。請更新 runtime 套件或 image、重新啟動 workers,並確認真正接受網頁請求的程序。

常見問題

哪一種輸出結果可以關閉 production 修補工單?

沒有任何單一輸出可以直接關閉工單。即使結果是 OK,仍應一併確認 serving SAPI、供應商 backport 狀態、所有相關的 vhost 或 container,以及套用修補後 workers 確實已重新啟動。