wordpress 網頁伺服器掃描攻擊與應對

網站又被太多連線連到連不上網站, 雖然網站掛在 cloudflare 後面, 還是被太多連線造成網站掛掉.

伺服器現況分析

從你提供的日誌來看,你的伺服器正在遭受大規模的自動化掃描攻擊。這些攻擊者利用工具不斷嘗試存取你多個 WordPress 網站的敏感目錄,例如 wp-includes 或 wp-admin。雖然 Apache 正確地攔截了這些請求並顯示 client denied,但短時間內湧入的龐大連線數已經讓你的系統吃不消。在重啟之前,load average 高達 56,這表示你的 CPU 負載已經爆表,且 1GB 的記憶體完全耗盡,迫使系統頻繁使用硬碟的 Swap 空間,這正是伺服器變得極度緩慢的主因。

重啟後的觀察

重啟 Apache 後,記憶體雖然釋放出了一些空間,load average 也降到了 22,但這個數值對 1GB 的小主機來說依然非常危險。日誌中出現的大量 TIME_WAIT 代表剛才有非常多連線被切斷。目前掃描行為明顯還在持續,如果不做進一步的防護,系統很快會再次因為記憶體不足而陷入卡頓。此外,你在這台小主機上跑了至少五個不同的 WordPress 網站,這會讓資源分配變得非常吃緊。

具體應對建議

既然你的伺服器在 Cloudflare 後面,最有效的辦法是到 Cloudflare 的後台開啟 Under Attack 模式,或者建立 WAF 防護規則。你可以設定一條規則:只要請求的路徑包含 wp-includes 或以 .php 結尾且位於敏感目錄,就直接在 Cloudflare 端阻擋或要求驗證。這樣惡意流量就不會直接撞擊你的 Apache。另外,建議你檢查各個網站的 .htaccess 檔案,確保已經關閉目錄瀏覽功能。如果預算允許,這台主機的記憶體建議增加到 2GB 以上,才能比較穩定地運行這麼多網站。


Cloudflare WAF 防護規則建議

既然你的日誌顯示攻擊者都在掃描 wp-includes 與 wp-admin 底下的特定 PHP 檔案,你可以直接在 Cloudflare 的 Security -> WAF 建立一條規則。這能讓惡意請求在到達你的 Ubuntu 伺服器前就被攔截,大幅降低 CPU 負載與記憶體消耗。

建議的 WAF 規則邏輯

你可以選擇 Block (直接阻擋) 或 Managed Challenge (要求過圖形驗證)。規則條件建議如下:

  • Field: URI Path
  • Operator: contains
  • Value: /wp-includes/
  • AND
  • Field: URI Path
  • Operator: ends with
  • Value: .php

這條規則會抓出所有嘗試直接執行 wp-includes 資料夾內程式碼的行為,這在正常的 WordPress 運作中幾乎是不需要的。


伺服器端優化建議

除了外層防護,你的主機目前資源非常緊繃,建議調整 Apache 的設定來避免記憶體被耗盡:

  • 降低 MaxRequestWorkers: 你的記憶體僅 1GB,如果這個數值設得太高,當攻擊來襲時,Apache 會開啟過多處理程序導致進入 Swap。
  • 調整 KeepAliveTimeout: 將這個數值改為 2 或 3 秒,讓閒置連線快點斷開,釋放資源給下一個請求。
  • 安裝 Fail2Ban: 雖然在 Cloudflare 後面,但如果你有安裝 mod_remoteip,Fail2Ban 依然可以根據日誌自動將頻繁掃描的 IP 加入系統防火牆阻擋。

Apache 記憶體優化設定

針對 1GB 記憶體的伺服器,我們必須嚴格限制 Apache 的行程數量,避免它把記憶體吃光導致系統進入 Swap 甚至當機。請根據你使用的 MPM 模式(通常是 event 或 worker)修改設定。

請編輯 /etc/apache2/mods-available/mpm_event.conf/etc/apache2/mods-available/mpm_worker.conf

Apache

<IfModule mpm_event_module>
    StartServers             2
    MinSpareThreads          10
    MaxSpareThreads          25
    ThreadsPerChild          25
    # 這是關鍵,限制最大同時連線數,1GB 建議設在 100-150 之間
    MaxRequestWorkers        100
    MaxConnectionsPerChild   1000
</IfModule>

連線控制優化

接著請編輯 /etc/apache2/apache2.conf,調整連線回收的速度:

  • KeepAlive On: 保持開啟,但要縮短時間。
  • MaxKeepAliveRequests 100: 限制每個連線的請求數。
  • KeepAliveTimeout 2: 原本預設通常是 5 秒,縮短到 2 秒可以讓無用的連線趕快斷開。

針對 wp-includes 的本地端防護

雖然 Cloudflare 擋了第一層,但在伺服器本機端也可以加上這段設定,直接在 Apache 層級拒絕非法存取。請將此段加入你的 VirtualHost 設定中:

Apache

<Directory "/var/www/*/wp-includes">
    <Files "*.php">
        Require all denied
    </Files>
</Directory>

這樣即便攻擊者繞過 Cloudflare 直接連到你伺服器的 IP,Apache 也會直接回絕請求,不會去執行 PHP 程式,能省下大量 CPU 運算。

設定完成後,請記得執行 sudo apachectl configtest 確認沒語法錯誤,再重啟服務:

sudo systemctl restart apache2


在 Ubuntu 系統中,這類設定通常有兩個地方可以放,取決於你想針對單一網站還是全伺服器生效。

1. 針對特定網站(建議做法)

如果你想針對特定的 WordPress 網站進行防護,請到 /etc/apache2/sites-available/ 目錄下找對應的設定檔。例如你的網站名稱可能是 vpn.conf000-default.conf

你可以使用這個指令列出所有啟用的設定檔路徑:

ls /etc/apache2/sites-enabled/

然後使用編輯器開啟該檔案:

sudo nano /etc/apache2/sites-available/你的檔案名稱.conf

將防護程式碼放在 <VirtualHost *:80><VirtualHost *:443> 的區塊內即可。


2. 針對伺服器所有網站

因為你這台主機跑了 vpn, jasonfonts, stackoverflow, krita 等多個網站,如果你想一次全部保護,可以修改全域安全性設定檔:

sudo nano /etc/apache2/conf-available/security.conf

將這段程式碼貼在檔案的最末端:

Apache

<Directory "/var/www/*/wp-includes">
    <Files "*.php">
        Require all denied
    </Files>
</Directory>

<Directory "/var/www/*/wp-content/uploads">
    <Files "*.php">
        Require all denied
    </Files>
</Directory>

補充:我也順便幫你加上了 uploads 資料夾的 PHP 阻擋,因為那是駭客最常上傳惡意後門程式的地方。


3. 套用並重啟

如果你是修改 security.conf,請確保該設定檔已啟用:

sudo a2enconf security

最後檢查語法並重啟 Apache:

sudo apachectl configtest

sudo systemctl restart apache2


你可以將新的規則邏輯直接加入現有的表達式中。為了讓規則更嚴謹,我們使用括號將 wp-includes 的路徑與 .php 副檔名組合起來。

修改後的 Cloudflare WAF 規則表達式如下:

SQL

(http.request.uri.path contains "/cgi-bin/") 
or (http.referer contains "binance.com") 
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path targets_lib_path_suffix ".php")

或是更直覺的寫法:

SQL

(http.request.uri.path contains "/cgi-bin/") 
or (http.referer contains "binance.com") 
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path matches ".*\.php$")

設定說明

  • 為什麼要加 AND: 如果只阻擋 /wp-includes/,會連帶擋掉正常的 CSS 或 JS 檔案,導致網站排版壞掉。加上 .php 的條件後,就只會針對該目錄下的程式執行檔進行阻擋,這是最安全的作法。
  • 建議動作 (Action): 既然你目前的 Log 顯示這全是惡意掃描,建議將此規則的 Action 設為 Block(阻擋)或 Managed Challenge(驗證碼)。

後續檢查

設定完成後,你可以觀察 Cloudflare 的 Security -> Events,看是否有攔截到來自 /wp-includes/ 的請求。如果攔截成功,你 Ubuntu 伺服器上的 Apache error.log 應該就不會再出現這些 IP 的掃描紀錄,系統負載也會隨之下降。


既然無法使用 Matches 運算子,我們可以改用比較基礎的 containsends with 來組合。這在 Cloudflare 免費版或一般方案都能運作。

修改後的 WAF 規則建議

你可以將表達式改成以下內容,這樣就不需要 Matches:

SQL

(http.request.uri.path contains "/cgi-bin/") 
or (http.referer contains "binance.com") 
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path contains ".php")

為什麼這樣寫有效

  • contains “.php”: 雖然沒有正則表達式那麼精準,但絕大多數針對 wp-includes 的攻擊都是直接存取 .php 檔案。在正常情況下,WordPress 核心不會讓使用者從瀏覽器直接讀取該目錄下的 PHP 檔案,所以這條規則非常安全。
  • 組合條件: 透過 and 將目錄與副檔名綁在一起,可以確保不會誤擋到 wp-includes 裡的圖片或樣式表(CSS/JS)。

操作步驟

  1. 登入 Cloudflare,進入 Security > WAF
  2. 點擊現有規則旁邊的 Edit
  3. 點擊右下角的 Edit expression 切換到純文字模式。
  4. 將上面的代碼貼上並點擊 Deploy

設定完成後,建議你先觀察半小時,看伺服器的 load average 是否有從 22 慢慢降下來。如果還有其他特定路徑在報錯,我們可以再繼續擴充這條規則。


好的,我們把 wp-content/uploads 的防護也併入。在 WordPress 中,uploads 資料夾是用來存放圖片和媒體檔的,絕對不應該出現任何可執行的 .php 檔案。如果有人嘗試在裡面執行 PHP,那幾乎可以確定是駭客上傳了後門程式。

更新後的 Cloudflare WAF 表達式

請將規則更新為以下內容:

SQL

(http.request.uri.path contains "/cgi-bin/") 
or (http.referer contains "binance.com") 
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path contains ".php")
or (http.request.uri.path contains "/wp-content/uploads/" and http.request.uri.path contains ".php")

規則說明與後續建議

  • 阻擋 uploads 內的 PHP: 這是非常強效的防護。駭客最常見的手法是利用外掛漏洞上傳一個名為 shell.phpinfo.php 的檔案到圖片區。現在這條規則會在對方執行這些後門時,直接在 Cloudflare 端切斷連線。
  • 確認負載: 更新規則後,你可以再次觀察伺服器的 top 指令或 load average。如果規則奏效,連線數(Connection Counts)裡的 ESTABLISHED 數量應該會顯著減少,因為惡意請求在進入你的 Apache 之前就被擋掉了。
  • 檢查其他目錄: 你的日誌中還提到了 wp-admin/css/colors/ectoplasm/ 這種奇怪的掃描,這通常是針對特定外掛漏洞。目前的規則已經涵蓋了最危險的兩個區域(includes 和 uploads)。

要查看 Cloudflare 攔截了哪些 IP,請按照以下步驟操作,這能幫你確認防護規則是否發揮作用:

1. 進入 Cloudflare 事件日誌

登入 Cloudflare 後,在左側選單點擊 Security(安全性) > Events(事件)。

2. 查看活動摘要

在該頁面你會看到一個圖表和下方的清單。你可以從清單中看到:

  • Action taken: 如果顯示 Block,表示該請求已被成功攔截。
  • Rule ID: 確認是否為剛才設定的那條 WAF 規則。
  • IP address: 攻擊者的來源 IP。
  • Path: 對方嘗試存取的路徑(例如 /wp-includes/xxx.php)。

3. 使用篩選功能(選用)

如果事件太多,你可以點擊 Add filter,選擇 Service 等於 WAF,或是直接搜尋特定路徑,這樣就能精確看到針對 WordPress 敏感目錄的攻擊頻率。


觀察伺服器壓力是否釋放

在 Cloudflare 設定好之後,建議你在 Ubuntu 終端機執行 uptimetop

  • 如果 load average 從原本的 20-50 降到 2 以下,說明 Cloudflare 已經幫你的 CPU 擋掉了大半的工作。
  • 如果負載依然很高,請再執行一次 netstat -n | awk '/^tcp/ {print $6}' | sort | uniq -c | sort -n,看看 ESTABLISHED 的數量有沒有減少。

如果負載還是降不下來,可能還有其他非 PHP 的資源存取(例如大量的圖片請求)在消耗頻寬,到時候我們再針對那些行為調整規則。

About the author

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *