這篇需要 SSH 操作
這篇文章的操作需要透過 SSH 連進伺服器執行。還不熟悉 SSH?請先看SSH 連線教學。
備份做完了。接下來要搞清楚攻擊者在你的網站裡塞了什麼。
這一步的重點是只掃不清。先把所有感染點全部找出來,列成清單,之後再一次清乾淨。邊掃邊刪會讓你漏掉互相關聯的後門。
以下所有指令都是 SSH 進伺服器後直接跑的。範例路徑用 /home/runcloud/webapps/SITENAME,請替換成你的實際網站目錄。
內容導覽
先看 index.php 有沒有被動過
WordPress 的 index.php 是所有前台請求的入口,也是攻擊者最愛動手腳的地方。正常內容只有三行:
<?php
define( 'WP_USE_THEMES', true );
require __DIR__ . '/wp-blog-header.php';用 cat -n 打開來看行號:
cat -n /home/runcloud/webapps/SITENAME/index.php超過十行,或出現 goto、eval、base64_decode、一堆看不懂的變數名——那就是被植入了。
全站惡意程式碼掃描
下面這組指令從五個角度掃。整段複製貼上,一次跑完:
cd /home/runcloud/webapps/SITENAME
echo "=== 含 eval + base64 ==="
grep -rl "eval.*base64_decode\|base64_decode.*eval" --include="*.php" . 2>/dev/null
echo "=== 含 goto 混淆 ==="
grep -rl "goto [a-zA-Z0-9_]\{10,\}" --include="*.php" . 2>/dev/null
echo "=== 含可疑函數 ==="
grep -rl "str_rot13\|gzinflate\|gzuncompress\|assert(" --include="*.php" . 2>/dev/null
echo "=== 根目錄下的非標準 PHP ==="
find . -maxdepth 1 -name "*.php" ! -name "wp-*" ! -name "index.php" \
! -name "xmlrpc.php" ! -name "license.php" | head -30
echo "=== 最近 3 天內被修改的 PHP ==="
find . -name "*.php" -mtime -3 -not -path "./wp-content/cache/*" | head -50每段在掃什麼
- eval + base64:最經典的惡意程式碼寫法。攻擊者把實際程式碼用 base64 編碼,執行時再解碼跑
eval()。正常的 WordPress 外掛極少這樣寫。 - goto 混淆:用大量
goto跳轉把程式碼打亂,讓人看不懂。後面接超長隨機標籤名(10 字元以上)是明確的混淆特徵。 - 可疑函數:
str_rot13做字元旋轉、gzinflate/gzuncompress做壓縮解壓、assert()可以當eval()用。正常外掛出現這些的機率很低。 - 根目錄非標準 PHP:WordPress 根目錄下合法的 PHP 就那幾個(
wp-*.php、index.php、xmlrpc.php)。其他的像hiroshi.php、item.php,幾乎都是後門。 - 最近被修改的 PHP:你最近沒動過程式碼,但有 PHP 檔案在 3 天內被改過——那很可能是攻擊者的手筆。排除
cache/目錄是因為快取外掛會正常產生 PHP 快取檔。
掃描結果怎麼讀
- 空結果 = 該類型沒命中,是好事。
- 命中的檔案路徑會列出來,先記下來,之後統一處理。
- 在
wp-includes/裡命中不一定是惡意的——WordPress 核心的 HTML parser 確實用了goto。用cat打開看內容再判斷。
檢查檔案有沒有被鎖
有些惡意程式會用 Linux 的檔案屬性保護自己。設了 immutable 旗標之後,就算是 root 也不能直接刪除或覆寫:
lsattr /home/runcloud/webapps/SITENAME/*.php
lsattr /home/runcloud/webapps/SITENAME/wp-includes/*.php | grep "\-i\-"輸出裡看到 ----i--------- 帶 i 的,就是被設了 immutable。解除方法:
chattr -i 檔案路徑另外也要注意 ACL。如果 ls -la 輸出的權限欄尾巴有個 + 號,代表有額外的 ACL 規則。清除方法:
setfacl -b 檔案路徑掃完之後要注意的事
不是所有命中都是惡意的
有些合法外掛確實會用到 base64_decode(處理圖片、解碼授權金鑰)。掃到命中的檔案,一定要用 cat 打開看一下再判斷。
判斷準則很簡單:看得懂程式碼在做什麼的,可能是正常的;通篇都是亂碼變數名和編碼字串的,是惡意的。
掃描結果存下來
建議把掃描結果導到檔案,方便之後對照:
上面那整段掃描指令 > /tmp/scan-result-$(date +%Y%m%d).txt 2>&1清完之後再跑一次同樣的掃描,跟第一次的結果比對,確認沒有漏掉。
惡意程式不斷自動出現怎麼辦
你刪了一個檔案,過幾分鐘同名檔案又出現了。
這代表有一個還活著的 PHP-FPM worker 在即時執行惡意程式碼,不斷把後門寫回來。遇到這種狀況,先不要繼續掃——直接跳到清除階段的「停掉 PHP-FPM pool」步驟,斷掉它的執行環境再回來掃。
這些指令只掃 PHP 檔案
惡意程式有時候會偽裝成 .ico、.jpg、.png 副檔名,但裡面其實是 PHP 程式碼。如果 Nginx / Apache 設定允許 .htaccess 把這些副檔名當 PHP 執行,那掃 PHP 就不夠了。
掃完 PHP 沒發現問題、感染跡象卻還在的話,就要往這個方向查。
貼給你的 AI 用
已經 SSH 進伺服器了?把下面這段貼給 ChatGPT 或 Claude,他會幫你判斷掃描結果:
我需要掃描 WordPress 網站有沒有被植入惡意程式碼。我已經 SSH 進伺服器了。
我的環境:
- 網站路徑:[填入,例如 /home/runcloud/webapps/mysite]
- PHP 版本:[填入]
請給我一組完整的掃描指令(grep eval+base64、goto 混淆、可疑函數、根目錄非標準 PHP、最近修改的 PHP),我貼回結果給你判斷哪些是惡意的、哪些是正常的。每個命中的檔案幫我分析要不要刪。SSH 操作注意事項
SSH 指令送出去就是送出去了,沒有 Ctrl+Z。操作前請注意:
- AI 給的指令,跑之前自己看一遍,確認路徑和檔名是對的再按 Enter。
- 不要整段複製貼上一口氣跑完。一次一個指令,看到結果再下一步。
- 刪除和覆蓋操作不可逆。備份沒做完之前,不要動任何清除步驟。
- 不確定的時候就停下來問。問 AI、問主機商、問會的朋友,都比直接跑好。
SSH 基礎教學請看這篇。


