🔥 懶人包:
全球熱銷超過百萬次的 WordPress 主題 Avada 與其搭配外掛 Fusion Builder,被驗出存在 CVE-2026-18431 未授權遠端程式碼執行漏洞,CVSS 評分高達 9.8(近乎滿分)。更驚人的是,這個需要串連六個步驟才能觸發的複雜攻擊鏈,是由 Wordfence 旗下的 AI 代理人「Argus」在完全無人介入的情況下、僅花兩小時就自動挖出並生成攻擊展示程式碼。攻擊者不需要帳號密碼、不需要你點任何連結,就能直接在你的主機上寫入並執行惡意 PHP 檔案。強烈建議立刻將 Avada 更新至 7.16.1 以上、Fusion Builder 更新至 3.16.1 以上 ⚠️
🔍 前往 Avada 官方網站 [1]
內容目錄
🧐 這個漏洞到底在講什麼?先用生活化比喻搞懂
先別急著被一堆英文縮寫嚇跑,我們把你的 WordPress 網站想像成一棟裝潢華麗、戒備森嚴的企業總部大樓。Avada 佈景主題就是這棟大樓的建築結構與外觀設計,而Fusion Builder 外掛則是負責在裡面隨時搬動隔間、重貼壁紙的萬能工程機器人。開發商為了不用每次小修小補都把整棟大樓拆掉重蓋,特別在系統深處留了一條叫做「Fusion Patcher」的維護通道,讓高階主管(也就是你這位網站管理員)可以直接把小型修繕藍圖傳給工程機器人施工 🏢
正常情況下,只有拿著最高權限通行證的人才能打開這條通道。但這次的漏洞就像大樓保全系統一次出現了六個各自看起來都不嚴重、但串在一起卻致命的破口。一個完全沒有通行證的陌生人(未授權的攻擊者),不用跟大門警衛核對身分(無須登入),只要包裝一份看起來人畜無害的假信件(操控輸入參數),就能讓一樓接待員誤以為是正常公文,一路呈遞到原本只限主管使用的維修排程系統裡 🙅♂️
最終,工程機器人乖乖照著這份假藍圖,在機房裡幫駭客蓋出了一個不受控的暗門。也就是說,駭客完全不需要偷到你的帳號密碼,也不用騙你點釣魚連結,就能直接在你的主機上放置惡意程式,等於整棟大樓的鑰匙都交出去了 🚨
傳統的資安掃描工具比較像玩「打地鼠」,看到一個外掛就快速戳一戳、找有沒有單一個明顯的漏洞,屬於「廣度優先」策略。而這次立功的 AI 代理人 Argus,更像是玩解謎密室逃脫的高手——它不滿足於找到單一把鑰匙,而是把六道各自看似無關的機關(六個攻擊步驟)串起來推理,直到找出整條真正能打開最終大門的路徑,這就是所謂的「深度優先」策略,也是它能在短短兩小時內比對出六步攻擊鏈的關鍵 🔑
📖 事情的來龍去脈:一場人類與 AI 的資安接力賽
這起事件在資安圈之所以引發熱烈討論,關鍵不只在漏洞本身,而在於它的發現方式。它並非由人類研究員耗費數月手動挖掘,而是由知名 WordPress 資安公司 Wordfence 旗下代號「Argus」的深度學習 AI 代理人所發現。與 Wordfence 另一款偏向「廣度優先」的 AI 工具 PRISM 不同,Argus 被設計成能像頂尖人類研究員一樣,把多個微小的系統操作串聯起來思考的「深度優先」漏洞獵人 🧠
| 時間節點 | 具體進展與處置動作 |
|---|---|
| 2026-07-30 | Wordfence 的 AI 代理人 Argus,在完全無人介入的自動化運作下,僅耗時約 兩小時,於擁有百萬次銷售紀錄的 Avada 主題中,找出需精準觸發六個連續步驟的複雜攻擊鏈,並自動生成完整的攻擊展示程式碼(PoC) |
| 2026-07-30(同日) | Wordfence 為其進階付費用戶(Premium/Care/Response)部署虛擬修補規則 |
| 2026-08-10 | 開發商 ThemeFusion 接獲通報後迅速確認問題 |
| 2026-08-25 | ThemeFusion 正式釋出包含安全性修補的 Avada 7.16.1 與 Fusion Builder 3.16.1 版本 |
| 2026-08-28 | 本篇報告資料檢索/更新日期,截至此時尚未有確切證據顯示漏洞已被廣泛利用、未列入 CISA 已知漏洞目錄 |
| 2026-08-29 | Wordfence 預計將虛擬修補規則下放至所有免費版用戶 |
值得特別留意的是,資安專家指出這種需要串聯六步驟才能成功的複雜攻擊鏈,若換成人類研究員逐步拼湊,可能得花上數週甚至數月。雖然截至目前尚未觀察到公開的大規模濫用案例,但由於 CVSS 評分高達 9.8、攻擊門檻又極低,地下論壇極可能已經透過比對新舊版本源碼差異(Patch Diffing)還原出攻擊手法,隨時準備發動自動化掃描攻擊,這代表拖延更新的每一天都是在跟時間賭運氣 ⏰
💡 碎碎念:什麼是「Patch Diffing」?
這就像是駭客拿到修補前後的兩份藍圖,逐格比對哪裡被改掉了。只要抓出差異的那幾行程式碼,就能反推出原本的漏洞長什麼樣子,等於官方每次公開修補,都間接洩漏了漏洞細節給還沒更新的網站帶來風險,這也是為什麼資安圈常說「一日漏洞(One-Day)」比未知的「零時差(Zero-Day)」擴散得更快 🌠
⚠️ 對我的網站有什麼實質影響?
此漏洞屬於資安事件中的「最壞情況」。因為攻擊者可以直接寫入並執行任意 PHP 檔案,這等於把網站與伺服器的最高控制權整個雙手奉上,一旦被入侵,可能導致以下災難性後果 🚫
| 影響層面 | 具體災情描述與後果 |
|---|---|
| 資料庫與機密外洩 | 攻擊者可讀取 wp-config.php 檔案取得資料庫密碼,進而竊取全站會員資料、顧客購買紀錄,甚至商業機密 |
| 網站被植入惡意後門 | 駭客會在系統深處建立隱蔽後門或新增幽靈管理員帳號,即使你日後修補了漏洞,他們仍能隨時進出網站 |
| 勒索軟體與主機停擺 | 伺服器檔案可能被全面加密勒索贖金,主機也可能被拿去挖礦,導致網站效能耗盡而完全癱瘓 |
| 品牌信譽與 SEO 毀滅 | 網站可能被神不知鬼不覺竄改成釣魚跳板,導致 Google 將網站列入黑名單,SEO 排名瞬間歸零 |
如果把資安漏洞的嚴重程度想成消防局的火警分級,CVSS 9.8 分大概就是「一棟大樓同時多處起火、且沒有任何灑水系統啟動」的最高等級出勤標準。攻擊向量寫著AV:N/AC:L/PR:N/UI:N,翻成白話就是:駭客不用靠近你家(可遠端發動)、不用費工破解(攻擊複雜度低)、不用先偷到任何鑰匙(不需權限)、也不用騙你點什麼(不需使用者互動),四個「零門檻」條件全部到齊,才會湊出這麼接近滿分的可怕分數 ⚠️
🎭 四種情境對應:你屬於哪一種,該怎麼辦?
🙋 一般網站管理者(部落格主、中小型商店)
你不需要看懂任何程式碼,只需要做兩件事:確認 Avada 與 Fusion Builder 的版本號碼,並在確認過舊之後立刻更新。這是決定你的網站是否暴露在風險中最關鍵、也最容易被忽略的一步 🌠
建議行動:最高優先。 立刻登入後台檢查版本,若 Avada ≤ 7.16 或 Fusion Builder ≤ 3.16,請比照文末的三分鐘自救 SOP 立刻處理,這件事完全不需要程式背景,十分鐘內就能做完 👍
👨💻 網站代管商/獨立開發者(DevOps)
若你手上管理多個客戶的 Avada 站台,光靠人工逐一點擊後台更新效率太低。建議透過 WP-CLI 批次盤點所有站台的主題與外掛版本,並優先在 WAF 層級部署阻擋規則作為修補前的緩衝防線 🔧
建議行動:高優先。 這類讀者請直接參考後段技術深潛篇的排查指令與應急防堵設定 ⚙️
🏢 企業商業用途(電商、會員制網站)
若你的網站涉及會員個資或線上金流交易,這起漏洞不只是技術問題,更直接牽涉個資法與合規責任。一旦資料外洩被證實,企業面對的可能不只是商譽受損,還有主管機關的裁罰與客戶信任的流失 🚫
建議行動:極高優先,且需留存證據。 除了更新與備份,建議同步啟動內部資安事件應變流程,保留稽核日誌以供後續調查與法遵佐證 ⚠️
🚨 高風險情境:你以為跟自己無關,其實正好踩雷
一位接案的網頁設計師,同時幫五、六個客戶用 Avada 快速搭站,交件後就很少再回去維護。他心想「網站架好又沒出過問題,應該不用天天盯著更新通知」,卻沒意識到,正是這種「架好就放著不管」的心態,讓所有站台長期停留在有漏洞的舊版本,變成駭客眼中一整排毫無防備、且完全不需要密碼就能長驅直入的自動化提款機 🆘
🚨 畫重點!千萬別踩雷:若伺服器環境未配置資源隔離(例如未設定 open_basedir、未採用容器化隔離),攻擊者取得 Web Shell 後,極易透過本機權限提升拿到 Root 權限,導致整台主機淪陷,甚至進一步橫向攻擊同主機上的其他無辜網站 🙅♂️
🔍 技術深潛篇:CVE 底層原理拆解(給 DevOps 看)
從系統架構層面來看,這個漏洞是個很有教育意義的經典案例:兩個各自看起來都不算致命的設計,在互相交互之下衍生出跨越 Theme 與 Plugin 邊界的複雜漏洞鏈 📊
| 項目 | 內容 |
|---|---|
| CVE 編號 | CVE-2026-18431 |
| CVSS v3.1 評分 | 9.8(Critical) |
| CVSS 向量 | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — 可遠端發動、攻擊複雜度低、不需任何權限與使用者互動,對機密性/完整性/可用性皆造成全面衝擊 |
| 漏洞成因分類 | 授權驗證缺失(CWE-862)+輸入驗證不充分的致命結合 |
| 受影響版本 | Avada Theme ≤ 7.16、Fusion Builder Plugin ≤ 3.16 |
| 安全版本 | Avada ≥ 7.16.1、Fusion Builder ≥ 3.16.1 |
🧑🔧 DevOps 小知識:漏洞根本原因不是傳統的記憶體破壞或 SQL Injection
核心爆發點位於 ThemeFusion 開發的Fusion Patcher機制,這原本是設計給站長不用升級整包主題、就能接收特定檔案修補程式(Hotfixes)的輕量維護通道,因此它在應用程式中天生就擁有極高的檔案系統寫入權限。問題在於 Avada 與 Fusion Builder 在處理外部請求時,未能嚴格守護信任邊界(Trust Boundaries):當前端接收到未經驗證的 HTTP 請求,由於缺乏強制身分校驗,攻擊者得以操控請求參數逐步影響後端 PHP 執行時的上下文與信任狀態,使系統誤把匿名請求當成合法管理員操作,越權呼叫 Fusion Patcher,最終把夾帶惡意 PHP 代碼的偽造修補檔直接寫入伺服器實體磁碟 🔧
🎯 攻擊鏈路:六個環環相扣的步驟,缺一不可
此攻擊的觸發門檻極低,唯一前置條件是目標網站需同時啟用 Avada 與 Fusion Builder,並存在特定的管理員發布內容作為切入點。Argus 揭露的攻擊路徑必須嚴格遵循以下六個步驟 🕵️
| 攻擊鏈步驟 | 技術操作說明 |
|---|---|
| ❶ 暴露攻擊輸入點 | 攻擊者透過面向公眾的請求端點,成功傳遞受控的惡意參數輸入 |
| ❷ 觸及內部行為 | 該輸入突破初步路由,抵達原本不應對匿名使用者開放的內部邏輯處理區塊 |
| ❸ 越權調用特權元件 | 內部的 Fusion Patcher 核心特權元件被異常喚醒,脫離其預期安全上下文被呼叫 |
| ❹ 影響信任狀態 | 攻擊者傳遞的請求資料,在該次請求生命週期內竄改了系統的信任狀態(例如全域變數覆寫或安全標記繞過) |
| ❺ 越權執行管理維護 | 系統基於被竄改的信任狀態,授權執行理應僅限管理員操作的檔案維護動作(寫入修補檔) |
| ❻ 突破檔案控制寫入後門 | 維護程式的檔案處理控制未能有效限制寫入檔案的副檔名與目的地路徑,導致惡意 PHP 檔落地 |
這有點像悠遊卡加值機出現漏洞:正常情況下,機器只認證你插入的悠遊卡本身是不是合法卡片。但如果有人能透過某個小手法,讓機器誤以為「目前操作的是店員的管理員卡」,即使插進去的還是你自己的普通卡,機器卻已經誤判成具備開櫃權限。這次漏洞的第四步「影響信任狀態」,就是類似讓系統誤判請求來源身分的手法,是整條攻擊鏈能夠成功的關鍵轉折 🔑
✅ 已確認的影響:任意檔案寫入與未授權 RCE。攻擊者可完全繞過 WordPress 登入與 Token 驗證機制,只要惡意 PHP 檔案成功寫入對外可存取的目錄(例如 wp-content/uploads/),僅需一次 GET 請求,即可以 Web 伺服器使用者身分(如 www-data)執行任意系統指令 💯
🟡 合理推論:大規模自動化武器化與殭屍網路擴張。考量到 Avada 全球高達百萬安裝量,此漏洞潛在攻擊面極其廣泛。雖然目前尚未觀察到公開的濫用案例,但地下論壇極可能已透過源碼差異比對還原六步攻擊鏈,短時間內針對 admin-ajax.php 或 fusionJSVars 特徵的大規模殭屍網路掃描可能會激增 ⚠️
🔴 假設情境:權限擴張與整台主機淪陷。若該站點建置於未做資源隔離的伺服器環境,攻擊者取得 Web Shell 後,極易透過本機權限提升取得 Root 權限,不僅該主機可能完全淪陷,更可能進一步對內網基礎設施發動橫向移動攻擊 🚫
✅ 資安排查與自我檢查 Checklist
🤖 重要提醒:以下指令與排查流程由 Gemini 產生、Claude 複查
雖然已盡力對照常見實務經驗與 WP-CLI 官方文件,但仍可能因伺服器環境、權限設定或外掛版本差異而產生疏漏。正式環境(尤其是生產站)的高風險操作——包含更新、停用、刪除檔案、變更權限或執行批次腳本——請務必由熟悉該站架構的專業人員進行最後確認與執行,切勿直接複製貼上後就按下 Enter 🧙
如果你的網站曾經跑過 Avada ≤ 7.16 或 Fusion Builder ≤ 3.16,現在真正棘手的問題已經不是「有沒有漏洞」,而是「在你把漏洞修掉以前,這段時間有沒有東西已經被寫進網站」。CVSS 9.8 分、不需要密碼就能觸發,代表這條攻擊鏈的門檻極低,任何暴露在網路上的舊版站台都值得比照「疑似已遭掃描」的心態排查,而不是看到版號更新完就直接收工 🧐
🕵️ 你的網站到底有沒有被摸過?先把現場一層一層翻出來
因此這一節不會只丟一條「跑完看綠色就結案」的指令,而是照著 環境判斷 👉 盤點 👉 Log 👉 檔案 👉 帳號 👉 排程 👉 加固 👉 鑑識快照 的順序,把可能留下的痕跡一層層縮小範圍。每個步驟都會先講「為什麼要這樣查」,再給實際指令與預期輸出,最後才是「看到結果該怎麼分岔判斷」,並且涵蓋 單一網站/獨立多站/Multisite 三種常見架構 📜
🔥 一句話先記住:「Avada 7.16.1+Fusion Builder 3.16.1」代表你已經跨過這個漏洞的版本安全邊界,但它不等於「網站歷史上從來沒被摸過」。如果舊版本曾經對外暴露過,版本更新與入侵排查應該視為兩件不同的工作,缺一不可 🚷
🧭 ㊀ 先搞懂你在管的到底是什麼:一個網站、一整台主機,還是一個 Network?
這一步看起來很無聊,卻是後面所有批次指令能不能安全下手的地基。判斷錯環境架構,很容易一個指令下錯地方,把 A 客戶的站當成 B 客戶的站處理 🌠
| 環境 | 你會看到的結構 | 正確思路 | 常用 WP-CLI 定位方式 |
|---|---|---|---|
| 💠 單一網站 | 一個 WordPress 安裝,一個 Avada 佈景 | 直接在該網站目錄操作即可 | –path=”$WP_PATH” |
| ❇️ 獨立多站 | 一台主機/VPS 上有多個各自獨立的 WordPress | 每個 wp-config.php 都代表一個完全獨立的安裝,各自的 Avada、資料庫互不相通 | –path=”$path” |
| ✴️ Multisite | 一個 WordPress Network,底下掛了多個 Site | Avada 佈景與 Fusion Builder 檔案屬於整個 Network 共用,不是每個 Site 各裝一份 | –url=”$url” |
💠 單一網站:先確認 WP-CLI 真的站在 WordPress 裡
決策原理:先確認目前路徑真的能載入 WordPress,再往下查佈景與外掛,比直接執行一長串指令安全得多,也能避免對錯誤目錄下毒手 ⚙️
※下方路徑 /var/www 請自行替換為網站的真實路徑,並注意路徑一律以雙引號包覆。
WP_PATH="/var/www/example.com/public_html"
if wp --path="$WP_PATH" core is-installed; then
echo "OK: WordPress installation detected."
else
echo "ERROR: WordPress installation not detected."
fi
預期輸出:
OK: WordPress installation detected.
分支判斷:
- ✅ 顯示 OK 👉 可以進入盤點階段。
- 🟠 顯示 ERROR 👉 先停手,不要把找錯的目錄當成網站繼續操作。
- 🟡 若網站路徑含空格或特殊字元,務必保留 “$WP_PATH” 的雙引號,不要自行拿掉。
❇️ 獨立多站:先把每一個真正的 WordPress 找出來
決策原理:不論是 HestiaCP、cPanel 或自行維運的 VPS,「同一台主機上有很多個 WordPress」不等於 Multisite。這時應該從各站的 wp-config.php 建立一份完整清單(Inventory)🔎
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
if wp --path="$path" core is-installed 2>/dev/null; then
printf 'WordPress: %s\n' "$path"
fi
done
預期輸出:
WordPress: /var/www/site-a/public_html WordPress: /var/www/site-b/public_html WordPress: /var/www/site-c/public_html
分支判斷:
- ✅ 每個路徑都能順利通過 👉 可以據此建立獨立多站的盤點清單。
- 🟠 找到 wp-config.php 卻無法載入 WordPress 👉 先確認 PHP 版本、檔案權限或路徑是否正確,不要直接更新。
- 🟡 同一個網站被掃到多份 wp-config.php(例如 Staging 副本)👉 先人工確認哪一份才是正式站,避免誤更新到備份或測試環境。
✴️ Multisite:判斷是否真的存在 Network
決策原理:wp site list 是 Multisite 專屬指令;WP-CLI 官方文件將它定義為列出 Multisite 安裝中的 Site 清單,若目標並非 Multisite,執行時會直接回傳錯誤,這本身就是一種判斷方式。
WP_PATH="/var/www/network/public_html"
if wp --path="$WP_PATH" core is-installed; then
if wp --path="$WP_PATH" site list \
--fields=blog_id,url \
--format=table; then
echo "OK: Multisite network confirmed."
else
echo "INFO: Not a Multisite installation (or command failed)."
fi
else
echo "ERROR: WordPress installation not detected."
fi
預期輸出:
blog_id url 1 https://example.com/ 2 https://shop.example.com/ 3 https://blog.example.com/ OK: Multisite network confirmed.
分支判斷:能列出多個 Site 👉 進入 Multisite 流程;指令回傳錯誤(例如 This is not a multisite installation.)👉 這台不是 Multisite,請改用單一網站或獨立多站流程判斷。
🧑🔧 DevOps 小知識:「獨立多站」像同一棟大樓裡租了三家公司,各自有自己的門、帳本與倉庫;Multisite 則比較像同一家公司底下有三個部門,共用同一套佈景與外掛檔案。外觀看起來都是「三個網站」,但資料庫、Avada 佈景與 Fusion Builder 的更新邏輯完全不同,千萬別混著操作 🚫
🔎 ㊁ 雙元件盤點:Avada 佈景與 Fusion Builder 外掛,兩份版號都要對
這次漏洞的特別之處在於,攻擊鏈同時涉及佈景主題(Avada)與外掛(Fusion Builder)兩個獨立元件,因此盤點時不能只查其中一個。官方公告的受影響範圍是 Avada ≤ 7.16、Fusion Builder ≤ 3.16,安全版本則是 Avada ≥ 7.16.1、Fusion Builder ≥ 3.16.1 📊
💠 單一網站:一次把兩份版號都問清楚
決策原理:版本盤點應以 WordPress 自己認得的 Theme/Plugin metadata 為主,而不是自己 grep PHP 檔案內容去猜版本,避免誤判。
WP_PATH="/var/www/example.com/public_html"
echo "=== Avada Theme ==="
wp --path="$WP_PATH" theme get "Avada" \
--fields=name,status,version,update_version 2>/dev/null \
|| echo "找不到名稱為 Avada 的佈景,請用 wp theme list 核對實際 slug"
echo "=== Fusion Builder Plugin ==="
wp --path="$WP_PATH" plugin get "fusion-builder" \
--fields=name,status,version,update,update_version 2>/dev/null \
|| echo "找不到 fusion-builder 外掛,請用 wp plugin list 核對實際 slug"
預期輸出:
=== Avada Theme === name: Avada status: active version: 7.16 update_version: === Fusion Builder Plugin === name: fusion-builder status: active version: 3.16 update: available update_version:
🚨 畫重點!千萬別踩雷:因為 Avada 與 Fusion Builder 都不是掛在 WordPress.org 官方目錄上的免費套件,update_version 欄位通常不會自動顯示官方新版本號,這裡的 –dry-run 與一般 wp.org 外掛的行為不同,詳細原因留到本節後段「Dry-run 的限制」說明,這裡先把「目前版本」問清楚就好 🙅♂️
分支判斷:
- 🔴 Avada ≤ 7.16 或 Fusion Builder ≤ 3.16,任一項符合 👉 視為受影響,進入備份/應急/修補流程。
- 🟢 兩者皆 ≥ 7.16.1/3.16.1 👉 版本條件已解除,但若網站曾經使用過舊版,仍建議走一次入侵排查。
- 🟠 其中一項查不到 👉 用 wp theme list 或 wp plugin list 核對實際 slug 命名,也要確認不是查錯了網站路徑。
❇️ 獨立多站:逐站盤點,結果一律帶上路徑
決策原理:每個獨立 WordPress 都有自己的 Avada/Fusion Builder 安裝狀態,因此每一站都要用 –path 分開查,並用 heredoc 把批次腳本寫成可重複執行的檔案,方便日後定期排查。
cat <<'EOF' > "$HOME/avada-inventory.sh"
#!/usr/bin/env bash
set -euo pipefail
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
theme_ver="$(wp --path="$path" theme get "Avada" \
--field=version 2>/dev/null || true)"
fb_ver="$(wp --path="$path" plugin get "fusion-builder" \
--field=version 2>/dev/null || true)"
if [ -n "$theme_ver" ] || [ -n "$fb_ver" ]; then
printf 'Site: %s | Avada: %s | FusionBuilder: %s\n' \
"$path" "${theme_ver:-N/A}" "${fb_ver:-N/A}"
fi
done
EOF
chmod +x "$HOME/avada-inventory.sh"
"$HOME/avada-inventory.sh"
預期輸出:
Site: /var/www/site-a/public_html | Avada: 7.16.1 | FusionBuilder: 3.16.1 Site: /var/www/site-b/public_html | Avada: 7.16 | FusionBuilder: 3.16 Site: /var/www/site-c/public_html | Avada: 7.15.2 | FusionBuilder: 3.15.9
分支判斷:這份結果就是第一張「風險地圖」,B、C 兩站應優先列入修補名單;A 站版本雖已跨過安全邊界,仍可安排一次歷史排查,因為它可能曾在舊版時期暴露過 ⭐
✴️ Multisite:佈景與外掛檔案只盤點一次,Site 層再各自確認啟用狀態
決策原理:Multisite 共用同一套 Avada 佈景與 Fusion Builder 外掛檔案,因此不能把每個 Site 當成一份獨立安裝來盤點兩次。
WP_PATH="/var/www/network/public_html"
wp --path="$WP_PATH" theme get "Avada" \
--fields=name,status,version
wp --path="$WP_PATH" plugin get "fusion-builder" \
--fields=name,status,version,update,update_version
wp --path="$WP_PATH" site list \
--field=url
分支判斷:版本以 Network 安裝的檔案為核心;Site 層再用 –url=”$url” 逐一確認各站是否真的啟用 Avada(Multisite 允許各 Site 選用不同佈景)。WP-CLI 官方也將 –url 定義為 Multisite 指定目標 Site 的標準做法。
🧾 ㊂ Log 排查:不是看到 404 就緊張,而是找「特徵路徑+時間+結果」
官方技術分析指出,攻擊鏈的關鍵入口涉及 wp-admin/admin-ajax.php 與 fusionJSVars 相關的資料交換特徵。因此排查 Log 時,真正有價值的不是尋找某個「神奇 IP」,而是確認是否曾出現對應路徑、異常負載參數與可疑回應碼的組合 🔍
💠 單一網站:先找得到 Log,再做特徵搜尋
決策原理:不同主機環境的 Access Log 路徑完全不同,不要把某個固定路徑當成所有伺服器的標準答案。
LOG_FILE="/var/log/apache2/access.log"
if [ -f "$LOG_FILE" ]; then
grep -Ei \
'admin-ajax\.php|fusionJSVars|fusion-builder|avada_ajax' \
"$LOG_FILE" |
tail -n 100
else
echo "LOG NOT FOUND: $LOG_FILE"
fi
預期輸出:
LOG NOT FOUND: /var/log/apache2/access.log
這不是失敗,而是提醒你:先找出實際的 VirtualHost/Web Server Log 位置(Nginx 常見於 /var/log/nginx/,或依主機商面板路徑而異)。如果找到 Log,可能看到類似:
... "POST /wp-admin/admin-ajax.php HTTP/1.1" 200 ... ... "GET /wp-content/uploads/2026/08/xr7z.php HTTP/1.1" 200 ...
分支判斷:
- 🟢 只找到零星 admin-ajax.php 請求且皆為正常後台行為 👉 先不用緊張,但仍建議往下做檔案排查。
- 🟡 admin-ajax.php 出現異常大量、異常負載參數的 POST 請求 👉 提高事件優先級,比對同一時間的檔案建立紀錄。
- 🔴 POST 請求之後緊接著出現對 uploads 或佈景目錄內陌生 .php 檔案的 GET 請求且回應 200 👉 進入「已中招/疑似中招」流程。
❇️ 獨立多站:每個 VirtualHost 都要對到自己的 Log
決策原理:不要只查其中一站,因為只要曾啟用舊版 Avada,任何一站都可能是受影響對象。
LOG_ROOT="/var/log"
find "$LOG_ROOT" -type f \
\( -name "*access*.log" -o -name "*access*.log.*" \) \
-print0 |
while IFS= read -r -d '' log; do
matches="$(grep -Ei \
'admin-ajax\.php|fusionJSVars|fusion-builder|avada_ajax' \
"$log" 2>/dev/null || true)"
if [ -n "$matches" ]; then
printf '\n===== %s =====\n' "$log"
printf '%s\n' "$matches" | tail -n 50
fi
done
分支判斷:某站出現命中 👉 標記該站需要進一步鑑識;全部沒有命中 👉 風險相對降低,但不能證明「絕對沒被摸過」,因為 Log 可能已輪替、遺失或分散在其他服務。
✴️ Multisite:同一份 Web Server Log,靠 URL/時間再定位 Site
LOG_FILE="/var/log/nginx/access.log"
if [ -f "$LOG_FILE" ]; then
grep -Ei \
'admin-ajax\.php|fusionJSVars|fusion-builder|avada_ajax' \
"$LOG_FILE" |
tail -n 100
fi
分支判斷:找到可疑時間點後,用 wp site list 取得 Site 清單,依 Log 中的 Host/URL 對照哪個 Site 受影響;不要只看「Avada 是否啟用」,因為各 Site 的啟用狀態可能不同。
🚨 畫重點:Log 裡出現 admin-ajax.php 不等於「一定成功入侵」——這是 WordPress 非常常見的正常端點;同樣地,完全沒找到可疑字串,也不能保證「完全沒被攻擊」。Log 只是證據之一,務必搭配下一節的檔案排查一起判斷 🙅
🗂️ ㊃ 檔案威脅狩獵:先查 uploads,再查整個佈景目錄
這個漏洞最終落地的動作是「任意檔案寫入」,因此 wp-content/uploads/ 是最值得優先看的位置;由於攻擊鏈涉及佈景主題自身的 Fusion Patcher 機制,wp-content/themes/Avada/ 目錄下是否被植入陌生檔案,同樣值得一併排查 📊
💠 單一網站:先找 uploads 與佈景目錄裡的可疑 PHP 檔
決策原理:正常 WordPress 媒體庫與佈景目錄不應該出現非官方安裝流程建立的可執行檔案,這裡先做低噪音、高價值的檢查。
WP_CONTENT="/var/www/example.com/public_html/wp-content"
UPLOADS="$WP_CONTENT/uploads"
THEME_DIR="$WP_CONTENT/themes/Avada"
echo "=== Uploads 可疑檔案 ==="
if [ -d "$UPLOADS" ]; then
find "$UPLOADS" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print
else
echo "UPLOADS DIRECTORY NOT FOUND: $UPLOADS"
fi
echo "=== 佈景目錄近 7 天內異動檔案 ==="
if [ -d "$THEME_DIR" ]; then
find "$THEME_DIR" -type f -iname "*.php" -mtime -7 -print
fi
預期輸出:
=== Uploads 可疑檔案 === /var/www/example.com/public_html/wp-content/uploads/2026/08/xr7z.php === 佈景目錄近 7 天內異動檔案 === (無輸出代表這 7 天內沒有 PHP 檔案被異動)
分支判斷:
- 🟢 兩項都沒有輸出 👉 這一項沒有發現異常。
- 🔴 uploads 出現不屬於你部署流程的 PHP/可執行檔 👉 不要直接刪除,先保留檔案時間、權限、雜湊與副本供鑑識。
- 🟡 佈景目錄內出現你自己合法更新造成的異動 👉 記錄原因(例如手動升級時間點),不要把所有異動一律當成惡意檔案。
❇️ 獨立多站:每站各自檢查,結果要帶上路徑
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
uploads="$path/wp-content/uploads"
if [ ! -d "$uploads" ]; then
continue
fi
hits="$(find "$uploads" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print)"
if [ -n "$hits" ]; then
printf '\n===== SUSPICIOUS EXECUTABLE FILES: %s =====\n' "$path"
printf '%s\n' "$hits"
fi
done
分支判斷:每站獨立判斷,不要看到 A 站乾淨,就順手把 B、C 站也視為乾淨。
✴️ Multisite:Uploads 通常位於同一個 Network 安裝之下
WP_PATH="/var/www/network/public_html"
UPLOADS="$WP_PATH/wp-content/uploads"
if [ -d "$UPLOADS" ]; then
find "$UPLOADS" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print
fi
分支判斷:找到異常檔案後,依路徑與時間對照 Network Site 清單、Access Log 與部署紀錄,不要只因為檔案位於 Network Uploads 目錄,就直接認定某一個 Site 是受害者。
👤 ㊄ 帳號與權限排查:駭客留下的未必只有檔案
若網站曾遭成功入侵,檔案只是其中一種持久化方式;WordPress 管理員帳號與角色權限同樣值得一起檢查 🕵️♀️
💠 單一網站:先列出所有 Administrator
WP_PATH="/var/www/example.com/public_html"
wp --path="$WP_PATH" user list \
--role=administrator \
--fields=ID,user_login,user_email,display_name,user_registered \
--format=table
預期輸出:
ID user_login user_email display_name user_registered 1 admin admin@example.com Site Admin 2025-11-02 09:15:00 9 supportacc ops@example.com Support Account 2026-08-16 03:40:00
分支判斷:任何不認識的管理員帳號都值得進一步確認,尤其是註冊時間落在漏洞公開日(2026-07-30)之後的帳號要優先查證,但「陌生」本身不等於惡意,也可能是既有維運商帳號。
❇️ 獨立多站:每個 WordPress 各自列管理員
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
printf '\n===== %s =====\n' "$path"
wp --path="$path" user list \
--role=administrator \
--fields=ID,user_login,user_email,display_name,user_registered \
--format=table
done
分支判斷:某站出現未知管理員 👉 優先標記該站進行事件調查,不要因為同一台主機其他站看起來正常就跳過它。
✴️ Multisite:先分清「Network 層級」與「Site 層級」帳號
WP_PATH="/var/www/network/public_html"
wp --path="$WP_PATH" user list \
--fields=ID,user_login,user_email,display_name,user_registered \
--format=table
分支判斷:發現未知帳號後,再確認它究竟是 Network 層級的 Super Admin,還是單一 Site 的一般管理員;不要只看到帳號存在就直接刪除,先確認權限範圍再處理。
⏰ ㊅ 排程與擴充套件狀態:有沒有東西被安排「自己跑」?
💠 單一網站
決策原理:檢查 WordPress Cron 是否出現不熟悉的事件、Hook 名稱或異常頻率,這是常見的持久化手法之一。
WP_PATH="/var/www/example.com/public_html"
wp --path="$WP_PATH" cron event list \
--fields=hook,next_run_gmt,recurrence \
--format=table
分支判斷:出現未知 Hook 👉 先查它來自哪個佈景/外掛,不要看到名稱陌生就直接刪除,避免誤刪合法排程。
❇️ 獨立多站
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
printf '\n===== CRON: %s =====\n' "$path"
wp --path="$path" cron event list \
--fields=hook,next_run_gmt,recurrence \
--format=table
done
分支判斷:只針對有異常跡象的站深入追查,不要因為站台數量多就一次刪掉所有非預期 Cron。
✴️ Multisite
WP_PATH="/var/www/network/public_html"
wp --path="$WP_PATH" cron event list \
--fields=hook,next_run_gmt,recurrence \
--format=table
如果發現可疑事件,再搭配 Site URL、佈景/外掛清單與 Log 時間線一起交叉比對。
🧱 ㊆ 加固檢查:就算修好了,也把第二道門鎖起來
這起漏洞最根本的教訓之一,就是「檔案寫入」不能只靠應用程式本身把關。就算已經升級到安全版本,讓 uploads 目錄本身無法執行 PHP,可以當成長期存在的第二道防線,而不只是應急措施 🔧
Nginx:先「檢查」現況,不要貿然覆寫上線設定
決策原理:先確認目前是否已經有阻擋 uploads 執行 PHP 的規則,再決定要不要新增;直接貼一段設定檔到 Production 反而可能因為既有規則衝突而讓網站掛掉。
NGINX_CONF="/etc/nginx/sites-available/example.com.conf"
if [ -f "$NGINX_CONF" ]; then
grep -n "uploads" "$NGINX_CONF" || echo "尚未發現 uploads 相關限制規則"
else
echo "NGINX CONFIG NOT FOUND: $NGINX_CONF"
fi
分支判斷:這一步只做檢查,不直接覆寫既有設定;因為 Apache、Nginx、LiteSpeed 或主機商自訂面板(如 HestiaCP、cPanel)的實際架構不同,設定語法也不同,貼錯反而可能造成新問題,建議先在 Staging 驗證。
🧑🔧 DevOps 小知識:正式套用時,可參考本文前段提供的 location ~* ^/wp-content/uploads/.*\.php$ { deny all; } 這段 Nginx 規則,但套用前務必先用 nginx -t 檢查語法正確,確認無誤後再 systemctl reload nginx,而不是直接 restart 造成短暫斷線 ⚙️
📦 ㊇ 建立鑑識快照:看到異常時,先留證再動手清理
如果已經看到可疑檔案、帳號或 Log,不建議第一反應就是 rm -rf,因為刪掉之後反而可能把最有價值的證據一起刪掉 🧯
💠 單一網站
cat <<'EOF' > "$HOME/collect-avada-evidence.sh"
#!/usr/bin/env bash
set -euo pipefail
WP_PATH="/var/www/example.com/public_html"
EVIDENCE_DIR="$HOME/avada-evidence-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$EVIDENCE_DIR"
{
echo "=== Collected at $(date -Is) ==="
wp --path="$WP_PATH" core version
wp --path="$WP_PATH" theme get "Avada" \
--fields=name,status,version
wp --path="$WP_PATH" plugin get "fusion-builder" \
--fields=name,status,version
} > "$EVIDENCE_DIR/summary.txt"
wp --path="$WP_PATH" user list \
--role=administrator \
--fields=ID,user_login,user_email,display_name,user_registered \
--format=csv \
> "$EVIDENCE_DIR/administrators.csv"
find "$WP_PATH/wp-content/uploads" \
-type f \
-printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p\n' \
2>/dev/null \
> "$EVIDENCE_DIR/uploads-inventory.txt"
echo "Evidence directory: $EVIDENCE_DIR"
EOF
chmod +x "$HOME/collect-avada-evidence.sh"
"$HOME/collect-avada-evidence.sh"
預期輸出:
Evidence directory: /home/admin/avada-evidence-20260904_120000
分支判斷:已確定存在疑似入侵跡象 👉 先把這份 Evidence Directory 複製到受保護的獨立儲存位置,再進入清理與正式修補流程。
❇️ 獨立多站
SEARCH_ROOT="/var/www"
EVIDENCE_ROOT="$HOME/avada-evidence-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$EVIDENCE_ROOT"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
safe_name="$(printf '%s' "$path" | tr '/ ' '__')"
evidence="$EVIDENCE_ROOT/$safe_name"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
mkdir -p "$evidence"
wp --path="$path" user list \
--role=administrator \
--fields=ID,user_login,user_email,display_name,user_registered \
--format=csv \
> "$evidence/administrators.csv"
find "$path/wp-content/uploads" \
-type f \
-printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p\n' \
2>/dev/null \
> "$evidence/uploads-inventory.txt"
done
echo "Evidence root: $EVIDENCE_ROOT"
分支判斷:每個子目錄就是一個獨立站點的鑑識資料,後續才能把「哪個網站、哪個時間、哪個檔案」精準對起來,不會混淆。
✴️ Multisite
WP_PATH="/var/www/network/public_html"
EVIDENCE_DIR="$HOME/avada-multisite-evidence-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$EVIDENCE_DIR"
wp --path="$WP_PATH" core version \
> "$EVIDENCE_DIR/core-version.txt"
wp --path="$WP_PATH" site list \
--fields=blog_id,url \
--format=csv \
> "$EVIDENCE_DIR/sites.csv"
find "$WP_PATH/wp-content/uploads" \
-type f \
-printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p\n' \
2>/dev/null \
> "$EVIDENCE_DIR/uploads-inventory.txt"
echo "Evidence directory: $EVIDENCE_DIR"
分支判斷:Multisite 的證據應以 Network 為中心,再依 Site URL 與時間軸細分,不需要對同一套 Network 資料重複 dump 多次。
🛟 真的出事了怎麼救?從「先止血」一路走到「確認關門」
前一節解決的是「怎麼判斷」,這一節進入真正的維運 Runbook。特別提醒:Avada 與 Fusion Builder 都是透過 ThemeFusion 官方帳號購買下載的商用套件,並未上架 WordPress.org 官方目錄,這代表許多針對 wp.org 免費外掛設計的 WP-CLI 自動更新與 Checksum 比對指令,在這裡的行為會不太一樣,本節會逐一說明並提供對應的替代做法 📜
| 階段 | 目的 | 核心動作 |
|---|---|---|
| ① 判斷環境 | 避免操作錯網站 | 單站/獨立多站/Multisite |
| ② 盤點 | 知道誰受影響 | Avada 版本+Fusion Builder 版本 |
| ③ 備份 | 保留回復點 | DB+必要網站檔案 |
| ④ Dry-run/限制說明 | 先了解更新機制的侷限 | 商用套件無法比照 wp.org 自動比對 |
| ⑤ 更新 | 關閉漏洞 | 雙元件同步升級至安全版本 |
| ⑥ 驗證 | 確認修補真的完成 | 版本+完整性+功能+Log |
🔥 這裡最重要的閉環:
判斷環境 👉 盤點 👉 備份 👉 了解更新限制 👉 雙元件更新 👉 驗證。簡言之:不要把「後台顯示已更新」當成整件事結束 🙅
🚨 A 情境:已中招/疑似中招,先止血再修補
如果你已經在上一節找到可疑 PHP、陌生管理員、異常 Log 或其他明確入侵跡象,處理順序與「單純版本升級」不一樣。
💠 單一網站:先建立事件狀態紀錄
決策原理:疑似入侵時,最大的敵人不是漏洞本身,而是在沒有留下證據的情況下就直接動手清理。
WP_PATH="/var/www/example.com/public_html"
INCIDENT_DIR="$HOME/avada-incident-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$INCIDENT_DIR"
{
echo "=== Incident collection ==="
date -Is
echo "WP_PATH=$WP_PATH"
wp --path="$WP_PATH" core version
wp --path="$WP_PATH" theme get "Avada" --fields=name,status,version
wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,status,version
} > "$INCIDENT_DIR/summary.txt" 2>&1
echo "Incident evidence: $INCIDENT_DIR"
分支判斷:證據已建立 👉 接著進行止血;若是企業、電商或會員制網站,應同步通知內部資安或維運負責人,並比照事件應變流程留存紀錄。
❇️ 獨立多站:只隔離有證據的站,避免整台主機一起誤傷
INCIDENT_PATH="/var/www/site-b/public_html"
if wp --path="$INCIDENT_PATH" core is-installed; then
echo "Incident target confirmed: $INCIDENT_PATH"
else
echo "ERROR: target is not a WordPress installation."
fi
分支判斷:確認路徑正確 👉 再針對該站執行維護;不要把整個 /var/www 當成單一網站處理,也不要因為一站中招就連坐停掉所有站台。
✴️ Multisite:先把事件視為 Network 級問題
WP_PATH="/var/www/network/public_html"
wp --path="$WP_PATH" site list \
--fields=blog_id,url \
--format=table
wp --path="$WP_PATH" theme get "Avada" --fields=name,status,version
wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,status,version
分支判斷:任一 Site 出現明確入侵跡象 👉 因為佈景與外掛檔案是 Network 共用,應把整個 Network 都納入事件調查範圍,不能只處理出事的那個 Site。
🧯 B 情境:尚未確認中招,但現在還不能立刻升級?先做短期應急
短期應急的目標不是「修好漏洞」,而是縮短攻擊面暴露時間,等待維護窗口完成正式升級 🛟
🚨 短期應急 ≠ 正式修補。
邊界防護、鎖住檔案寫入權限或停用 Fusion Builder,都只是緩衝措施;真正治本的方法仍然是把 Avada 與 Fusion Builder 同步升級到安全版本 🦺
💠 單一網站:鎖住檔案寫入權限、視情況停用 Fusion Builder
決策原理:可以先透過 wp config set 在應用程式層鎖死後台的檔案編輯與外掛/佈景寫入,降低攻擊鏈第五、六步驟成功的機會,但這無法完全阻擋透過底層 API 的繞過攻擊 ⚙️
WP_PATH="/var/www/example.com/public_html" wp --path="$WP_PATH" config set DISALLOW_FILE_MODS true --raw --type=constant wp --path="$WP_PATH" config set DISALLOW_FILE_EDIT true --raw --type=constant wp --path="$WP_PATH" config get DISALLOW_FILE_MODS wp --path="$WP_PATH" config get DISALLOW_FILE_EDIT
預期輸出:
Success: Added the constant 'DISALLOW_FILE_MODS' to the 'wp-config.php' file with the value 'true'. Success: Added the constant 'DISALLOW_FILE_EDIT' to the 'wp-config.php' file with the value 'true'. true true
分支判斷:
- 🟢 網站近期不需要在後台安裝/更新任何外掛佈景 👉 可以保留這個設定,等排定維護窗口再解除並正式升級。
- 🟠 業務仍需要用後台介面調整 Fusion Builder 頁面配置 👉 這個設定不會影響前台頁面編輯功能本身,但會擋住後台的外掛/佈景安裝與內建檔案編輯器,請先確認團隊工作流程是否受影響。
❇️ 獨立多站:逐站鎖定,不要一次改動整台主機
INCIDENT_PATH="/var/www/site-b/public_html" wp --path="$INCIDENT_PATH" config set DISALLOW_FILE_MODS true --raw --type=constant
分支判斷:只影響 Site B,不應該連 Site A、Site C 的 wp-config.php 一起改動。
✴️ Multisite:Network 層級要一起考慮
WP_PATH="/var/www/network/public_html" wp --path="$WP_PATH" config set DISALLOW_FILE_MODS true --raw --type=constant
分支判斷:Multisite 只有一份 wp-config.php,這個設定會套用到整個 Network,因此套用前務必先確認不會影響其他 Site 團隊的正常維運節奏。
🧑🔧 DevOps 小知識:如果站台架在 WAF(例如 Cloudflare、AWS WAF)後方,也可以同步確認是否已啟用針對遠端程式碼執行與任意檔案上傳的防護規則集;Wordfence 已於漏洞公開當日為進階付費用戶部署虛擬修補規則,並在數週後下放至免費版用戶,這同樣屬於「短期應急」而非長期解方 🛡️
💾 備份:修補前先留下一條可以回家的路
💠 單一網站:資料庫+佈景外掛目錄
決策原理:雙元件更新主要改的是 Avada 佈景與 Fusion Builder 外掛的檔案,但網站內容、設定與媒體檔案仍可能需要恢復,因此至少要有資料庫備份,並依既有維運政策保留必要檔案 ❤️🩹
WP_PATH="/var/www/example.com/public_html"
BACKUP_DIR="$HOME/wp-security-backup"
STAMP="$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
wp --path="$WP_PATH" db export \
"$BACKUP_DIR/example-com_pre_avada_update_${STAMP}.sql"
tar -czf \
"$BACKUP_DIR/example-com_wp-content_pre_avada_update_${STAMP}.tar.gz" \
-C "$WP_PATH" \
"wp-content"
printf 'Backup completed:\n%s\n' "$BACKUP_DIR"
預期輸出:
Success: Exported to '/home/admin/wp-security-backup/example-com_pre_avada_update_20260904_123000.sql'. Backup completed: /home/admin/wp-security-backup
分支判斷:SQL 與檔案備份都存在 👉 進入下一步驟;任一備份失敗 👉 停止,不要進入正式更新。
❇️ 獨立多站:每個 WordPress 各自一份資料庫備份
SEARCH_ROOT="/var/www"
BACKUP_ROOT="$HOME/wp-security-backup"
STAMP="$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_ROOT"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
site_name="$(basename "$path")"
db_file="$BACKUP_ROOT/${site_name}_pre_avada_update_${STAMP}.sql"
echo "=== Backup: $path ==="
wp --path="$path" db export "$db_file"
done
分支判斷:某一站備份失敗,就把該站標記為未完成,不要因為其他站成功就直接進入批次更新。
✴️ Multisite:Network Database 不要重複 dump N 次
WP_PATH="/var/www/network/public_html"
BACKUP_DIR="$HOME/wp-security-backup"
STAMP="$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
wp --path="$WP_PATH" db export \
"$BACKUP_DIR/multisite_pre_avada_update_${STAMP}.sql"
tar -czf \
"$BACKUP_DIR/multisite_wp-content_pre_avada_update_${STAMP}.tar.gz" \
-C "$WP_PATH" \
"wp-content"
分支判斷:Database+必要檔案備份成功 👉 進下一步;不需要因為 Network 裡有 20 個 Site 就 dump 20 次同一個資料庫。
🧪 Dry-run 的限制:為什麼商用套件不能照搬 wp.org 那一套?
WP-CLI 官方的 wp plugin update/wp theme update 雖然都支援 –dry-run,但這個機制的資料來源是 WordPress.org 官方目錄;由於 Avada 與 Fusion Builder並未上架該目錄,執行後幾乎必然只會顯示「沒有可用更新」,這並不代表你已經是最新版,而是 WP-CLI 根本查不到官方目錄以外的版本資訊 🟡
WP_PATH="/var/www/example.com/public_html" wp --path="$WP_PATH" theme update "Avada" --dry-run wp --path="$WP_PATH" plugin update "fusion-builder" --dry-run
可能出現的輸出(僅供參考,實際訊息依 WP-CLI 版本而異):
Theme Avada is already at the latest version. Plugin fusion-builder is already at the latest version.
🚨 畫重點!千萬別踩雷:看到上面這種訊息絕對不能當成「已經是安全版本」的證據,正確做法是回到本文第3節「盤點」步驟裡查到的實際 version 欄位,跟官方公告的 7.16.1/3.16.1 手動比對,這一點是商用主題與一般 wp.org 免費外掛在 WP-CLI 使用習慣上最大的差異 🙅♂️
🔴 假設情境/未驗證項目:因為 Avada 與 Fusion Builder 屬於閉源商用套件,並未公開於 WordPress.org SVN 或公開 GitHub 儲存庫,因此無法比照開源外掛的做法,直接比對修補前後原始碼的 diff 內容來反推細節;本文能提供的防禦依據,僅限於 ThemeFusion 官方 Changelog 與 Wordfence 公開技術分析所描述的行為層級資訊,若需要更深入的程式碼層級差異,只能仰賴官方或授權資安廠商釋出的資料,這裡不做任何未經證實的臆測 【❓待確認:官方是否有釋出更細節的技術修補說明,需持續留意 ThemeFusion 官方公告】
🚀 C 情境:正式修補,雙元件同步升級才是唯一治本之道
由於 Avada 與 Fusion Builder 不在 WordPress.org 目錄裡,WP-CLI 沒有辦法單靠 wp theme update Avada 這種一行指令直接抓到官方新版;正確流程是先從 ThemeFusion 官方會員帳號下載最新安裝包,再用 WP-CLI 以本地 ZIP 檔覆蓋安裝 🔧
💠 單一網站:下載官方 ZIP 後強制覆蓋安裝
決策原理:wp theme install 與 wp plugin install 官方文件明確支援「本地 ZIP 檔路徑」作為安裝來源,搭配 –force 參數即可覆蓋既有版本,這是官方支援、非 wp.org 目錄套件最正規的 WP-CLI 更新方式,而不是把整包手動改名硬塞進去。
WP_PATH="/var/www/example.com/public_html"
PACKAGE_DIR="$HOME/avada-packages"
# ※ 以下兩個 ZIP 請事先從 ThemeFusion 官方會員帳號下載,
# 並確認版本號正確為 7.16.1 與 3.16.1 以上
AVADA_ZIP="$PACKAGE_DIR/Avada_7.16.1.zip"
FUSION_ZIP="$PACKAGE_DIR/fusion-builder_3.16.1.zip"
if [ ! -f "$AVADA_ZIP" ] || [ ! -f "$FUSION_ZIP" ]; then
echo "ERROR: 找不到官方安裝包,請先從 ThemeFusion 會員後台下載最新版本 ZIP"
else
wp --path="$WP_PATH" theme install "$AVADA_ZIP" --force
wp --path="$WP_PATH" plugin install "$FUSION_ZIP" --force
wp --path="$WP_PATH" theme get "Avada" --fields=name,version
wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,version
fi
預期輸出:
Installing Avada (7.16.1) Removing the old version of the theme... Theme updated successfully. Success: Installed 1 of 1 themes. Installing Fusion Builder (3.16.1) Removing the old version of the plugin... Plugin updated successfully. Success: Installed 1 of 1 plugins. name: Avada version: 7.16.1 name: fusion-builder version: 3.16.1
分支判斷:
- ✅ 兩者版號都已更新到 ≥ 7.16.1/3.16.1 👉 進入下一步完整性驗證。
- 🟠 只有其中一項更新成功 👉 不要視為完成,因為官方公告明確指出兩者必須同步更新才能完全弭平漏洞,請先排查失敗原因(權限、磁碟空間、ZIP 損毀)再重試。
- 🟡 手上沒有官方最新 ZIP 檔 👉 先透過 ThemeFusion 會員後台或授權經銷商取得,不要從非官方來源下載安裝包,以免引入額外風險。
🚨 手動 FTP 更新的人請特別注意:若不透過 WP-CLI 而改用手動 FTP/SFTP 上傳,切勿直接把新版檔案覆蓋貼到舊資料夾上;請先將原有的 Avada 與 fusion-builder 資料夾整個改名或刪除,再上傳全新版本資料夾,避免駭客潛藏的後門檔案殘留在舊目錄中繼續運作 🙅
❇️ 獨立多站:一站一個完整閉環
WP_PATH="/var/www/site-a/public_html" PACKAGE_DIR="$HOME/avada-packages" AVADA_ZIP="$PACKAGE_DIR/Avada_7.16.1.zip" FUSION_ZIP="$PACKAGE_DIR/fusion-builder_3.16.1.zip" wp --path="$WP_PATH" theme install "$AVADA_ZIP" --force wp --path="$WP_PATH" plugin install "$FUSION_ZIP" --force wp --path="$WP_PATH" theme get "Avada" --fields=name,version wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,version
分支判斷:Site A 更新並驗證成功後,再把同樣流程套用到 Site B;不要「全部更新完最後才一起檢查」,這樣一旦某站出錯很難快速定位問題。
✴️ Multisite:佈景外掛檔案只更新一次,再逐 Site 驗證
WP_PATH="/var/www/network/public_html"
PACKAGE_DIR="$HOME/avada-packages"
AVADA_ZIP="$PACKAGE_DIR/Avada_7.16.1.zip"
FUSION_ZIP="$PACKAGE_DIR/fusion-builder_3.16.1.zip"
wp --path="$WP_PATH" theme install "$AVADA_ZIP" --force
wp --path="$WP_PATH" plugin install "$FUSION_ZIP" --force
wp --path="$WP_PATH" site list --field=url |
while IFS= read -r url; do
printf '\n===== %s =====\n' "$url"
wp --path="$WP_PATH" --url="$url" theme get "Avada" \
--fields=name,status,version
wp --path="$WP_PATH" --url="$url" plugin get "fusion-builder" \
--fields=name,status,version
done
分支判斷:佈景與外掛檔案版本只需要更新一次;Site 層則逐一確認是否正常載入與啟用,因為 Multisite 允許各 Site 選擇不同啟用狀態。
🔐 完整性驗證:Checksum 能做什麼、不能做什麼?
WordPress Core:可以正常使用官方 Checksum
WP_PATH="/var/www/example.com/public_html" wp --path="$WP_PATH" core verify-checksums
預期輸出:
Success: WordPress installation verifies against checksums.
🚨 畫重點!千萬別踩雷:WP-CLI 官方目前並未提供 wp theme verify-checksums 這個指令——這在 WP-CLI 官方 GitHub 儲存庫中,截至目前仍只是一項尚未實作的功能請求,而 wp plugin verify-checksums 的資料來源同樣是 downloads.wordpress.org 的官方 checksum API,對於未上架 wp.org 的 Fusion Builder 而言,執行後大機率只會得到「無法取得該外掛的 checksum」的警告,而不是驗證結果。這不是操作錯誤,而是這兩個指令原本就不支援商用套件 🙅♂️
替代做法:用官方安裝包自行做雜湊比對
決策原理:既然沒有官方 Checksum API 可用,退而求其次的做法是拿「剛從 ThemeFusion 官方下載、尚未安裝」的 ZIP 檔案,解壓後與伺服器上實際運作中的檔案逐一比對 SHA256 雜湊值,藉此確認伺服器上的檔案沒有被額外竄改或夾帶陌生檔案。
WP_PATH="/var/www/example.com/public_html"
PACKAGE_DIR="$HOME/avada-packages"
REFERENCE_DIR="$HOME/avada-reference-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$REFERENCE_DIR"
unzip -q "$PACKAGE_DIR/Avada_7.16.1.zip" -d "$REFERENCE_DIR"
# 產生「官方參考版」與「線上實際運作版」的檔案清單雜湊
find "$REFERENCE_DIR/Avada" -type f -exec sha256sum {} \; \
| sed "s|$REFERENCE_DIR/Avada/||" \
| sort \
> "$REFERENCE_DIR/reference-checksums.txt"
find "$WP_PATH/wp-content/themes/Avada" -type f -exec sha256sum {} \; \
| sed "s|$WP_PATH/wp-content/themes/Avada/||" \
| sort \
> "$REFERENCE_DIR/live-checksums.txt"
diff "$REFERENCE_DIR/reference-checksums.txt" "$REFERENCE_DIR/live-checksums.txt" \
|| echo "發現差異,請往下看分支判斷"
分支判斷:
- 🟢 diff 沒有輸出任何差異 👉 目前線上的 Avada 檔案與官方發行版一致。
- 🔴 出現「線上獨有、參考版沒有」的檔案 👉 這是最需要優先關注的訊號,代表有陌生檔案被額外放進佈景目錄,應立即納入鑑識與清理流程。
- 🟡 出現「雜湊值不同但檔名相同」的項目 👉 先確認是否為 WordPress 或伺服器環境正常寫入的快取/設定檔案(例如某些主題會在啟用時寫入 License 或設定快取),再判斷是否異常。
🚨 Checksum/雜湊比對不是「無罪證明書」。
它只能回答「這些檔案現在和官方發行的這一份是否一致」,無法回答資料庫、管理員帳號、mu-plugins 或 Web Server 本身是否曾遭入侵,務必搭配第3節的 Log、帳號、排程排查一起看 🦹♂️
❇️ 獨立多站/✴️ Multisite
雜湊比對的邏輯完全相同,差別只在於獨立多站要對每個 $WP_PATH 各自跑一次;Multisite 因為佈景檔案是 Network 共用,只需要對 Network 的佈景目錄跑一次即可,不需要對每個 Site URL 重複比對。
🧪 修補後回歸測試:版本對了,網站真的還活著嗎?
💠 單一網站
WP_PATH="/var/www/example.com/public_html"
wp --path="$WP_PATH" core is-installed
wp --path="$WP_PATH" theme get "Avada" --fields=name,status,version
wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,status,version
wp --path="$WP_PATH" cron event list \
--fields=hook,next_run_gmt,recurrence \
--format=table
預期結果:
- ✅ WordPress 可正常載入。
- ✅ Avada 顯示 7.16.1 或更新版本、Fusion Builder 顯示 3.16.1 或更新版本。
- ✅ 前台首頁與 Fusion Builder 頁面編輯功能正常。
- ✅ 後台可正常登入,Critical CSS 已重新產生。
- ✅ PHP Error Log 沒有突然大量增加 Fatal Error。
❇️ 獨立多站
採「一站一驗證」,Site A 完成後再處理 Site B、C:
WP_PATH="/var/www/site-a/public_html" wp --path="$WP_PATH" core is-installed wp --path="$WP_PATH" theme get "Avada" --fields=name,status,version wp --path="$WP_PATH" plugin get "fusion-builder" --fields=name,status,version echo "Verification target: $WP_PATH"
✴️ Multisite
Network 層驗證完成後,再逐一測試重要 Site:
WP_PATH="/var/www/network/public_html"
wp --path="$WP_PATH" site list --field=url |
while IFS= read -r url; do
printf '\n===== VERIFY SITE: %s =====\n' "$url"
wp --path="$WP_PATH" --url="$url" core is-installed
wp --path="$WP_PATH" --url="$url" theme get "Avada" \
--fields=name,status,version
done
分支判斷:任一 Site 出現錯誤 👉 暫停批次流程,先處理該 Site,不要繼續擴大變更範圍。
🔍 最後一輪 Log+檔案複查:確認修補後沒有新的異常
💠 單一網站
LOG_FILE="/var/log/nginx/access.log"
UPLOADS="/var/www/example.com/public_html/wp-content/uploads"
if [ -f "$LOG_FILE" ]; then
grep -Ei \
'admin-ajax\.php|fusionJSVars|fusion-builder' \
"$LOG_FILE" |
tail -n 50
fi
find "$UPLOADS" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print
分支判斷:更新後仍持續出現可疑請求或新的可疑檔案 👉 不要當成「已修好所以沒事」,應回到事件調查流程重新評估是否已遭入侵。
❇️ 獨立多站
逐站執行同樣檢查,結果一律保留網站路徑:
SEARCH_ROOT="/var/www"
find "$SEARCH_ROOT" -type f -name "wp-config.php" -print0 |
while IFS= read -r -d '' config; do
path="$(dirname -- "$config")"
uploads="$path/wp-content/uploads"
if ! wp --path="$path" core is-installed 2>/dev/null; then
continue
fi
printf '\n===== POST-PATCH CHECK: %s =====\n' "$path"
find "$uploads" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print 2>/dev/null
done
✴️ Multisite
WP_PATH="/var/www/network/public_html"
UPLOADS="$WP_PATH/wp-content/uploads"
find "$UPLOADS" -type f \
\( -iname "*.php" -o -iname "*.phtml" -o -iname "*.php*" \) \
-print
分支判斷:任何修補後新增的可疑檔案,都應回到「事件應變」流程,而不是單純重新更新一次佈景外掛。
🧾 最終驗收:這 8 格全部打勾,才算真正收工
| 驗收項目 | 單一網站 | 獨立多站 | Multisite |
|---|---|---|---|
| ① 環境判斷 | WP Path | 逐站 wp-config.php | Network + Site List |
| ② 雙元件版本 | 7.16.1/3.16.1+ | 每站 7.16.1/3.16.1+ | Network 7.16.1/3.16.1+ |
| ③ 備份 | DB+必要檔案 | 每站獨立 DB | Network DB+必要檔案 |
| ④ 官方 ZIP 覆蓋安裝 | 已完成 | 逐站完成 | Network 完成一次 |
| ⑤ SHA256 雜湊比對 | 一致 | 逐站一致 | Network 一致 |
| ⑥ Core Checksum | Verified | 逐站 Verified | Network Verified |
| ⑦ Log/檔案 | 無新異常 | 逐站無新異常 | Network/重要 Site 無新異常 |
| ⑧ 功能 | 前台+後台+Fusion Builder 編輯器 | 逐站驗證 | 重要 Site+Network |
✅ 完成標準:不是「後台顯示已是最新版」就算結束,而是版本已跨過 7.16.1/3.16.1、備份可用、雜湊比對正常、沒有新的可疑檔案/帳號/Log,前台、後台與 Fusion Builder 編輯功能也都正常 🦸
🏁 最終 DevOps Runbook:三種架構直接照這張地圖走
| 階段 | 💠 單一網站 | ❇️ 獨立多站 | ✴️ Multisite |
|---|---|---|---|
| ① 判斷 | –path=”$WP_PATH” | 逐一找 wp-config.php | wp site list |
| ② 盤點 | Avada+Fusion Builder 版本 | 每站雙元件版本 | Network 雙元件+Site 啟用狀態 |
| ③ 備份 | DB+必要檔案 | 每站獨立 DB | Network DB+必要檔案 |
| ④ 更新來源 | ThemeFusion 官方 ZIP | ThemeFusion 官方 ZIP | ThemeFusion 官方 ZIP |
| ⑤ 更新方式 | theme/plugin install –force | 一站一閉環 | Network 檔案更新一次 |
| ⑥ Version Verify | 7.16.1/3.16.1+ | 逐站 7.16.1/3.16.1+ | Network 7.16.1/3.16.1+ |
| ⑦ 完整性驗證 | Core Checksum+SHA256 比對 | 每站 Core+SHA256 | Network Core+SHA256 |
| ⑧ Threat Hunt | Log+Uploads+帳號 | 逐站檢查 | Network+Site 關聯 |
| ⑨ 功能驗證 | 前台/後台/編輯器 | 逐站驗證 | 重要 Site 驗證 |
🔥 最後一句話:這起漏洞真正值得留下來的 DevOps 經驗,不是某一條神奇指令,而是把「漏洞修補」做成一個可以重複執行、可以驗證、可以回復的維運流程:判斷環境 👉 盤點 👉 備份 👉 了解更新限制 👉 雙元件更新 👉 驗證。這樣即使下一次換成別的商用主題、別的 CVE,整套方法依然能繼續沿用 💪
📚 參考資料與延伸資源
- 📌 iThome 新聞|Avada WordPress 主題修補 9.8 分 RCE 漏洞,AI 代理 2 小時完成 6 段攻擊鏈 [81]
- 📌 CVE Record | CVE-2026-18431 [82]
- 📌 NVD – CVE-2026-18431 Detail [83]
- 📌 Wordfence Blog | Wordfence Argus Finds Complex 6-Step Critical RCE in Avada Theme with 1 Million Sales [84]
- 📌 The Repository Email | Wordfence’s new AI agent chains six flaws into a critical unauthenticated RCE in popular Avada theme [85]




