多數人以為,網站被駭之後只要把看得到的異狀清乾淨,導向陌生網址的跳轉、後台跑出來的垃圾廣告連結、勒索訊息,這場清理就算結束。其實真正棘手的部分,往往是那些從頭到尾都沒被看見的東西。攻擊者留在網站裡的隱藏程式碼或檔案,一般稱為後門(backdoor),它的作用跟被清掉的那些症狀不一樣,後門不負責製造麻煩,它負責讓麻煩可以隨時重來。
即使把跳轉頁面、垃圾內容全部清乾淨,只要這個隱藏的存取管道還留著,攻擊者就能繞過帳號密碼與登入畫面,直接回到網站裡,甚至把剛剛才刪掉的東西原封不動地種回去。這也是為什麼很多站方會遇到「明明已經處理過,過沒幾天問題又跑回來」的情況,清掉的只是後門養出來的結果,後門本身一次都沒被動到。
WordPress後門是什麼?
後門指的是攻擊者入侵網站之後,故意留下的一段隱藏程式碼或一支獨立檔案,讓他不用透過正常的帳號密碼、也不必經過登入畫面,就能繞道回到網站裡取得存取權。它跟其他惡意程式最大的不同,不在於做了什麼壞事,而在於它的角色定位。後門唯一的目的,是讓攻擊者能持續掌握存取權,也就是所謂的持久化(persistence)。Sucuri 的資安團隊在一起入侵清理案例的分析裡就指出,攻擊者放這類後門的用意,是確保就算網站上其他惡意軟體被抓到、被移除,他仍然保有進出這個網站的能力。
這一點也解釋了為什麼「後門」跟「被駭事件」不是同一件事。一次入侵裡真正造成損害的,通常是導流惡意網站的跳轉程式、注入垃圾連結的廣告程式碼、或是趁機挖礦的腳本,這些才是攻擊者想拿到的實際戰果。後門不是戰果,它是保底機制,負責在戰果被清掉之後,讓攻擊者還能再拿一次。兩者常常一起出現,但角色完全不同,一邊是攻擊者要的東西,一邊是攻擊者留給自己的備用鑰匙。
Sucuri 另一份案例分析講得更具體。一名客戶只是反映網站出現異常行為,深入調查之後才發現,網站裡藏著好幾個能讓攻擊者遠端執行任意程式碼的後門。Sucuri 也點出攻擊者一次放好幾個後門的用意,就是其中一個被發現了,還能靠其他的重新取得存取權。這也是為什麼網站清過一輪還是不對勁,往往是後門還在的徵兆,因為清理的人常常只處理了看得到的症狀,沒有找到真正讓攻擊者持續回得來的那段程式碼。也因此,把畫面上的異狀清乾淨,不等於清掉了後門本身,這兩件事必須分開檢查,少查一項,問題就會捲土重來。
後門的價值在於清不掉還能重新冒出來
要理解後門為什麼難處理,得先把它跟常見的攻擊酬載(payload)分開來看。導向惡意網站的跳轉程式、在頁面裡塞入垃圾內容或劫持連結的注入程式、能讓攻擊者直接下指令的網站殼層,這些本身都是攻擊者要的「效果」,清掉之後,表面上看起來事情就結束了。但如果同一個網站裡還有後門存在,清掉這些效果只是處理了症狀,同樣的東西,或是換一批新的東西,過一段時間又會重新出現。

Sucuri 在一份調查裡就整理了好幾起把惡意檔案藏進 mu-plugins 資料夾的案例。這些檔案性質完全不同,一支負責把訪客導向惡意網站,一支是能讓攻擊者遠端執行任意程式碼、取得近乎完整網站控制權的網站殼層,還有一支負責在頁面裡注入垃圾內容。三支檔案各自做的事完全不同,共同點是都挑了同一個會自動載入、又不容易被注意到的資料夾落腳,Sucuri 也把「透過後門維持持續存取」列為這類感染的目的之一。換句話說,讓這些效果能一直存在的,不是效果本身,而是攻擊者替自己保留的那條持續進出的管道。
這裡也該把「網站殼層(webshell)」這個常跟後門混用的詞講清楚。網站殼層是後門的一種具體形式,讓攻擊者能瀏覽伺服器上的檔案、上傳新的檔案、直接下指令,取得幾乎等同於完整伺服器的控制權。它不是另一個獨立的概念,而是後門具體展現出來的其中一種樣貌,後門提供的是持續存取的能力,網站殼層則是這個能力具體實現出來的介面。理解這層關係很重要,因為往後去排查可疑檔案時,看到一支疑似網站殼層的檔案,代表的不只是這支檔案有問題,而是背後很可能還有一整套後門機制在支撐它。
疏於檢查的 uploads 與停用不了的 mu-plugins
有兩個資料夾在 WordPress 的機制設計上,先天就對後門特別友善,不是巧合,而是機制本身留下的空隙。第一個是 mu-plugins(must-use plugins)。WordPress 的說明文件寫得很直白。這個目錄裡的檔案一律啟用,不需要透過後台開啟,使用者也無法不小心把它停用,而且載入順序是依字母順序、在一般外掛之前執行。也就是說,只要檔案放進這個資料夾,它就會在網站每一次載入時自動跑,而且後台外掛頁面完全看不到停用的選項,唯一的處理方式是直接把檔案刪掉。
更麻煩的是,同一份文件也明講,mu-plugins 裡的檔案不會出現在一般的更新通知裡,外掛頁面也不會顯示它們的更新狀態。多數人日常巡邏網站只會看外掛清單跟更新通知,根本不知道還有這個獨立分類存在,自然也不會想到要進去檢查。還有一個更少人知道的細節。WordPress 只會讀取 mu-plugins 目錄最上層的 PHP 檔案,不會往子目錄裡找。這也是為什麼後門經常偽裝成一個檔名看起來很普通的單一 PHP 檔案,直接丟在最上層。因為只要放進子目錄,WordPress 反而不會執行它,攻擊者當然不會選這個方式藏。
第二個容易被忽略的地方是 uploads 資料夾。這裡照設計只應該放圖片、影片這類媒體檔,幾乎沒有站方會想到要去檢查裡面有沒有夾帶程式檔案。前面提到 Sucuri 那起客戶反映網站異常的案例,mu-plugins 裡那支後門真正要執行的酬載,就藏在 uploads 底下一個看起來像普通文字檔的 index.txt 裡。問題出在 WordPress 本身並不會替這個目錄擋掉執行 PHP 的能力,主機如果也沒有另外設限,就算一支 PHP 檔案被上傳進 uploads 資料夾,伺服器一樣會乖乖執行它,等於留了一扇沒上鎖的門。設計用途跟實際風險之間的這個落差,正是攻擊者偏好挑這兩個資料夾下手的原因。

從編碼混淆到冒名核心檔案的偽裝手法
光靠「看檔名奇不奇怪」抓後門,遠遠不夠。實際案例裡出現過的手法,一層比一層更難用肉眼判斷。最基礎的一種是 ROT13,把每個英文字母在字母表裡位移十三位的簡單編碼,肉眼看起來像一串亂碼,但只要反向位移一次就能還原,並不是真正的加密。Sucuri 記錄過一支放在 mu-plugins 裡的檔案,用 ROT13 把遠端網址整段藏起來,解碼之後才看得到真正的酬載來源。文章裡也直接點出這個手法的本質。ROT13 是可逆的,不提供真正的安全性,它的作用只是躲過人眼一眼認出這是一個網址而已。
更進階的做法是多層 base64 編碼包裝,有的案例甚至用 AES-128-CBC 這種真正的加密演算法,把惡意網址與指令整個加密起來,不再只是編碼。還有一種常見手法是把敏感函式名稱拆開來寫,例如把 base64_decode 拆成好幾段字串再用點號串接回去,讓靜態掃描工具比對關鍵字時抓不到完整的函式名稱。這幾種手法的共同邏輯不是要騙過人眼一次,而是要同時躲過兩關,一關是掃描工具對已知特徵碼的比對,另一關是開發者快速瀏覽程式碼時的肉眼檢查。
還有一種偽裝更陰險。把函式名稱刻意取得像是 WordPress 核心函式,讓審查的人第一眼以為是正常程式碼。Sucuri 記錄過一個實例,攻擊者把 PHP 內建的 assert() 函式,拆成 _as_sert 這種中間插入底線的寫法,再包進一個自訂函式,取名為 wp_dbase_config_init(),聽起來就像是 WordPress 用來初始化資料庫設定的核心函式。程式碼裡還額外加了一段檢查 W3 Cache 這款熱門快取外掛是否存在的邏輯,製造出這是在做快取相容性檢查的假象,讓誰都不想去動一個可能讓網站快取壞掉的檢查程式。真正執行惡意程式碼的關鍵,其實是把底線字元全部拿掉之後,_as_sert 才會還原成貨真價實的 assert()。
後門一樣藏得進資料庫,被清掉的帳號還會自動長回來
只查檔案是不夠的,後門不一定是一支檔案,它一樣可以藏進資料庫裡。Sucuri 記錄過一支偽裝成合法外掛的後門,執行後會建立一個管理員權限的帳號,資料就寫在 wp_users 與 wp_usermeta 資料表裡,更棘手的是,這支後門會把自己從外掛清單裡藏起來,同時竄改使用者查詢的邏輯,讓這個新建的帳號不會出現在後台的使用者列表裡。也就是說,站方打開後台看使用者名單,畫面看起來完全乾淨,但資料庫裡其實已經多了一個具備完整管理權限的帳號。後台顯示的內容本身就已經被動過手腳,不能再當成唯一的判斷依據。
wp_options 資料表也能被拿來當酬載的儲存空間。前面提到用 ROT13 藏遠端網址的那支後門,實際的攻擊程式碼並不是存在檔案系統裡,而是存放在 wp_options 裡一個自訂的欄位,比檔案系統多了一層,一般只掃檔案的掃描工具根本碰不到這裡,自然也就找不到。
更頑固的一種變形,不是單純建立一個惡意帳號就結束,而是額外寫一段邏輯持續檢查這個帳號還在不在。Sucuri 記錄的案例裡,有一支根目錄下的獨立檔案,邏輯是每次執行都先查一次特定帳號是否存在,如果站方手動把它刪掉,程式下一次執行就會用攻擊者指定的密碼把它重新建立回來。這代表光靠刪帳號沒有用,必須連帶找到、清掉負責重新生成它的那段程式碼,否則帳號會一次又一次自己長回來。functions.php、wp-config.php 也是後門常見的落腳處,原理跟 mu-plugins 類似,這兩個都是 WordPress 每次載入一定會經過的地方,放在這裡才能保證持續運作;像 wp-user.php 這種偽造成系統檔名、直接丟在網站根目錄的獨立檔案,則是靠名字混在正常檔案裡,讓人不會想去動它。

安全外掛掃得到已知特徵,掃不到客製化的後門
安全外掛是合理的第一道防線,它能快速比對已知的惡意特徵碼,處理常見的感染狀況很有效率,這一點不該否定。但要知道它具體的侷限在哪裡,才不會誤以為掃過沒事就等於真的沒事。第一個限制是,安全外掛比對的是已知的特徵,攻擊者如果寫一支全新的客製化腳本,特徵碼資料庫裡沒有對應的紀錄,掃描自然就會放行,這也是前面提到那幾種編碼混淆手法真正的目的。第二個限制是,深度掃描本身很吃資源,網站檔案量一多,很容易撞到主機的執行時間或記憶體上限,導致掃描沒辦法跑完整個網站,酬載如果埋在很深的目錄層級,或是塞進體積很大的檔案裡,就更可能落在沒掃到的範圍。第三個限制是,多數安全外掛只在 WordPress 的應用層運作。如果後門的落腳處是主機層的設定,或是 WordPress 目錄之外的位置,外掛本身根本看不到。
安全外掛之外,還有幾個具體的人工排查動作可以補上這幾個缺口。從 WordPress.org 下載一份跟自己網站版本完全相同的乾淨核心檔案,用文字比對工具逐一比對 wp-config.php 與核心檔案,看看有沒有多出來的區塊,這個方法能揪出前面提到那種偽裝成核心函式的程式碼;外掛檔案也可以拿同版本的原始檔來比,Sucuri 那個 assert() 案例就是藏在 WooCommerce 的檔案裡。直接進 phpMyAdmin 查詢 wp_users 與 wp_usermeta 資料表,而不是只看後台的使用者列表,因為後台列表本身可能已經被後門動過手腳,查資料庫才是可靠的做法。在整個網站目錄裡搜尋 eval、base64_decode、gzinflate、str_rot13、assert 這幾個常被濫用的函式關鍵字,如果它們出現在不合理的位置,例如混在一長串看起來像亂碼的字元中間,就是很強的可疑訊號。最後,用 FTP 把檔案依最近修改時間排序,檢查有沒有自己完全想不起來動過的檔案,這個方法對揪出最近才被種進來的檔案特別有效。
檔案和資料庫要一起清,少一邊就留根
前面提過後門一樣能藏進資料庫,清理必須照著一套順序來,只清一邊等於沒清,少一步都可能留根。
第一步一定是先備份現況,即使現在的狀態是中毒的。這不是多餘的動作,後續要做鑑識分析、或是萬一操作過程中失誤改壞了正常檔案,都需要這份備份當退路。第二步處理檔案層面,包括刪除所有已經確認是可疑的檔案,像是 mu-plugins、uploads 目錄裡的異常檔案,以及偽造成核心檔名的獨立檔案;至於 WordPress 核心本身的檔案,直接用 WordPress.org 的最新版本整批覆蓋(wp-config.php 與 wp-content 資料夾不要覆蓋),不要只挑看起來可疑的那幾行去改,逐行修改很容易漏掉一部分,或是不小心把語法改壞。針對 uploads 目錄,還要額外加一道防護,在該目錄底下的 .htaccess 加入規則,擋掉這個目錄執行 PHP 的能力。這樣就算後面真的漏刪了什麼,放在裡面的 PHP 檔案也不會被伺服器執行,等於把整扇門直接鎖死。
第三步處理資料庫層面,包括查詢 wp_users 與 wp_usermeta,刪除確認為惡意的帳號;同時要搜尋 wp_options 裡有沒有不熟悉的欄位名稱,看起來像亂碼、或是跟已安裝的外掛與主題完全對不上的自訂欄位,一併刪除。這一步不能省,因為前面提到的重建機制很可能就藏在這些殘留設定裡,只刪帳號、不清這些欄位,帳號很可能又會被重新生回來。最後一步,是更新 wp-config.php 裡的 Authentication Unique Keys and Salts,讓現有的登入 session 全部失效,這個動作等於強制全站登出,要求所有帳號重新驗證身分,這樣即使攻擊者原本已經竊取到某個有效的登入狀態,那個狀態也會立刻失效。順手把 wp-config.php 加上 define('DISALLOW_FILE_EDIT', true); 停用後台的佈景主題與外掛編輯器,能少一個讓攻擊者或殘留邏輯重新寫入程式碼的管道。

抓到一個後門,通常代表還有下一個
攻擊者很少只留一道後門。對他們來說,持久化的價值本來就建立在備援之上。一個被發現、被清掉了,只要還有第二個、第三個在原地待命,整個入侵行動依然沒有結束。
2026 年 7 月中旬公開的一條 WordPress 核心漏洞鏈就具體示範了這個邏輯。編號 CVE-2026-63030 與 CVE-2026-60137 這兩個弱點,由資安研究公司 Searchlight Cyber 揭露,受影響的是 6.9 與 7.0 系列的核心版本,其中 SQL 注入的部分,甚至回溯到 6.8 系列都受影響,修補版本是 7.0.2。漏洞公開後,資安業者 Wiz 的研究團隊觀察到攻擊已經在野外實際發生,而且攻擊者入侵得手之後留下的後門不只一種。一支惡意外掛偽裝成合法的資安檢測工具「CMSmap」被安裝進網站裡,裡面其實藏著完整的後門介面,具備檔案管理、資料庫存取、連接埠掃描等功能,程式碼用十六進位字串拼接加上壓縮與編碼層層包裹,躲避掃描比對。另一支獨立的惡意外掛則悄悄註冊了一個自訂的 REST API 端點,權限驗證直接寫死為一律通過,只要送出一段 base64 編碼過的指令,伺服器就會解碼並執行。這兩套後門的運作方式完全不互相依賴,攻擊者只要在同一個網站裡各放一套,就算其中一套被抓到、清掉了,另一套依然能正常運作,攻擊者的存取權完全不受影響。
這也是為什麼,如果已經照前面的步驟認真清過一輪,檔案跟資料庫都處理了,但異常行為在幾天之內又跑回來,或是心裡並不確定自己是不是已經找全所有藏匿的位置,這代表用人工肉眼排查的極限可能已經到了。這種時候該做的是找專業的資安鑑識或網站維運團隊介入,而不是把同一套清理流程再重複一次,期待這次會有不一樣的結果。還有一種情況,是復發的根源根本不在 WordPress 裡,例如主機的排程工作定時把後門寫回去,或是同一台主機上其他網站的感染橫向擴散過來,這時候清再多次網站檔案與資料庫都碰不到,得往主機層去查。
把後門這件事放回最開始的脈絡來看,它從來不是被駭事件裡最顯眼的那個部分,反而常常是最安靜的那個。跳轉頁面、垃圾內容這些看得到的損害,清掉了就是清掉了;但那扇沒被找到的門,只要還開著,同樣的故事遲早會再上演一次。真正讓一次清理算數的,從來不是畫面看起來乾不乾淨,而是有沒有把攻擊者留給自己的那把備用鑰匙,連同它藏身的每一個角落,一起拿掉。
