Tới nội dung chính
hstation
Dịch vụDự ánVề tôiBlogThư viện nhạc

Bảo mật và sao lưu · 10 phút đọc · 2026-09-17

Website WordPress bị hack: tự kiểm dấu vết bằng WP-CLI

Success chỉ đúng với phép kiểm đang chạy, không đồng nghĩa toàn bộ website đã sạch. WP-CLI giúp đối chiếu checksum, đọc tài khoản admin và lưu dấu vết để kiểm tra lại sau mỗi lần sửa.

Tác giả
Quản trị viên
Đăng ngày
2026-09-17
Cập nhật
2026-09-17
Thời gian đọc
10 phút đọc
Tất cả bài viết

Website bị hack phải làm sao? Trước khi sửa bất cứ thứ gì, bạn cần biết cái gì đã bị thay đổi. Bài này là bốn phép kiểm bằng WP-CLI để tìm dấu vết trên một website WordPress bị hack, kèm thứ mỗi phép bắt được và thứ nó bỏ lọt.

Để đo cho thật, mình dựng một bản sao WordPress 7.1 trên máy rồi tự cài năm "dấu vết" vô hại, mô phỏng những thay đổi hay gặp khi site bị xâm nhập. Không có mã độc thật nào: mỗi tệp thêm vào chỉ in ra một câu. Chạy xong bốn phép kiểm không có nghĩa là site sạch 100%. Nó chỉ cho biết những chỗ mà bốn phép này nhìn tới.

Trước khi kiểm: làm trên bản sao

  1. Sao lưu đủ cơ sở dữ liệu và thư mục wp-content của site đang có vấn đề, theo bài Khôi phục website WordPress: sao lưu đủ hai phần. Bản sao lưu này là bằng chứng của hiện trạng, đừng ghi đè nó.
  2. Dựng bản sao từ bản sao lưu đó và kiểm trên bản sao.

Lý do: các lệnh dọn dẹp ở cuối bài ghi đè tệp lõi, cài lại plugin và xoá tài khoản. Làm sai trên bản sao thì dựng lại bản sao là xong. Làm sai trên site thật thì bạn mất luôn dấu vết cần tìm.

Năm dấu vết mình cài để thử

  1. Thêm một dòng chú thích vào cuối tệp lõi wp-includes/class-wp-embed.php.
  2. Thêm một tệp lạ wp-includes/wp-thu-la.php.
  3. Thêm một tệp wp-content/uploads/2026/09/cache.php.
  4. Thêm một dòng chú thích vào tệp chính của plugin Query Monitor.
  5. Tạo thêm một tài khoản quản trị tên quantri2.

Trước khi cài, cả bốn phép kiểm bên dưới đều sạch.

Kiểm 1: tệp lõi WordPress có bị sửa hay bị thêm không

bash
wp core verify-checksums

Lệnh này so từng tệp lõi với bản gốc của đúng phiên bản bạn đang chạy. Site sạch ra: "Success: WordPress installation verifies against checksums."

Sau khi cài dấu vết:

text
Warning: File doesn't verify against checksum: wp-includes/class-wp-embed.php
Warning: File should not exist: wp-includes/wp-thu-la.php
Error: WordPress installation doesn't verify against checksums.
  • Bắt được: dấu vết 1 (tệp lõi bị sửa) và dấu vết 2 (tệp lạ trong thư mục lõi).
  • Bỏ lọt: tệp PHP trong uploads. Lệnh này không nhắc gì tới nó, vì uploads không phải tệp lõi.

Kiểm 2: plugin có bị sửa không

bash
wp plugin verify-checksums --all

Site sạch ra "Success: Verified 3 of 3 plugins." Sau khi cài dấu vết:

text
query-monitor   query-monitor.php   Checksum does not match
Error: Only verified 2 of 3 plugins (1 failed).
  • Bắt được: dấu vết 4.
  • Giới hạn: lệnh so với bản trên kho plugin của WordPress. Plugin mua ngoài hay tự viết thì không có bản gốc để so; mình chưa đo ca đó.

Kiểm 3: WordPress bị hack tạo tài khoản admin lạ

bash
wp user list --role=administrator --fields=ID,user_login,user_registered

Site sạch chỉ có một dòng 1 demo 2026-09-07 03:55:28. Sau khi cài dấu vết, có thêm 2 quantri2 2026-09-17 03:22:02. Cột ngày tạo là chỗ nên nhìn: tài khoản quản trị sinh ra đúng quãng site có vấn đề là tài khoản đáng nghi nhất.

Một chi tiết dễ đọc nhầm: cột user_registered ghi theo giờ UTC. Mình tạo quantri2 lúc khoảng 10 giờ 22 sáng giờ Việt Nam, còn cột này ghi 03:22:02, lệch đúng 7 tiếng. Khi so với nhật ký hay thời điểm bạn nhận ra sự cố, nhớ cộng thêm 7 tiếng.

Trong wp-admin, trang Tài khoản cho thấy đúng điều đó:

Trang Tài khoản trong wp-admin, bộ lọc Quản lý có 2 mục. Dòng demo với email demo@wp-demo.local, vai trò Quản lý, 2 bài viết. Dòng quantri2 với email quantri2@vi-du.test, vai trò Quản lý, 0 bài viết.
Trang Tài khoản trong wp-admin, bộ lọc Quản lý có 2 mục. Dòng demo với email demo@wp-demo.local, vai trò Quản lý, 2 bài viết. Dòng quantri2 với email quantri2@vi-du.test, vai trò Quản lý, 0 bài viết.
  • Bắt được: dấu vết 5.

Kiểm 4: tệp PHP nằm trong thư mục uploads

bash
find wp-content/uploads -name "*.php"

Thư mục uploads là chỗ chứa ảnh và tệp tải lên. Trên site sạch, lệnh này không ra dòng nào. Sau khi cài dấu vết, nó ra wp-content/uploads/2026/09/cache.php.

Đây là phép duy nhất trong bốn phép bắt được dấu vết 3. Và dấu vết này đáng lo nhất, vì mình gọi thử tệp đó qua trình duyệt thì máy chủ trả 200 và chạy nó thật:

Trình duyệt mở đường dẫn tới tệp cache.php trong thư mục uploads, trang chỉ hiện một dòng chữ hstation-thu: PHP chay duoc trong uploads.
Trình duyệt mở đường dẫn tới tệp cache.php trong thư mục uploads, trang chỉ hiện một dòng chữ hstation-thu: PHP chay duoc trong uploads.

Chặn PHP chạy trong uploads

Trên máy chủ Apache, tạo tệp wp-content/uploads/.htaccess với nội dung:

text
<FilesMatch "\.php$">
Require all denied
</FilesMatch>

Gọi lại đúng tệp đó:

Trình duyệt mở lại đường dẫn tới cache.php sau khi thêm tệp .htaccess: trang Forbidden với dòng You don't have permission to access this resource.
Trình duyệt mở lại đường dẫn tới cache.php sau khi thêm tệp .htaccess: trang Forbidden với dòng You don't have permission to access this resource.
  • Tệp PHP trong uploads: 403.
  • Ảnh trong uploads: vẫn 200.

Cách này chỉ áp dụng khi máy chủ là Apache và đọc tệp .htaccess. Mình chưa thử trên Nginx.

Cách xử lý website WordPress bị hack sau khi thấy dấu vết: đọc kỹ chữ Success

Mình dọn năm dấu vết và đo từng bước. Có hai chỗ dòng "Success" dễ làm bạn tưởng đã xong.

1. Cài lại plugin bị sửa

bash
wp plugin install query-monitor --force

Sau đó "Success: Verified 3 of 3 plugins", và plugin vẫn giữ trạng thái đang bật.

2. Tải lại lõi WordPress

bash
wp core download --skip-content --force --version=7.1 --locale=vi

Đổi 7.1 và vi cho đúng phiên bản và ngôn ngữ site của bạn. Lần đầu lệnh báo "Error: Extracting a zip file requires ZipArchive." vì PHP dòng lệnh chưa bật extension zip. Mình chạy lại với php -d extension=zip thì được, mất 16.567 ms.

Kết quả:

  • Tệp lõi bị sửa (dấu vết 1) được phục hồi, dòng chú thích biến mất.
  • Tệp lạ wp-thu-la.php (dấu vết 2) vẫn còn nguyên. Tải lại lõi chỉ ghi đè tệp gốc, không xoá tệp thêm vào.

Chạy lại kiểm 1 lúc đó:

text
Warning: File should not exist: wp-includes/wp-thu-la.php
Success: WordPress installation verifies against checksums.

Dòng cuối là Success, dù tệp lạ vẫn nằm trong thư mục lõi. Đọc lướt dòng cuối là bỏ sót. Phải xoá tay tệp đó rồi chạy lại, đến khi không còn dòng Warning nào.

3. Xoá tệp PHP trong uploads và tài khoản lạ

bash
rm wp-content/uploads/2026/09/cache.php
wp user delete 2 --reassign=1 --yes

--reassign=1 chuyển bài viết (nếu có) của tài khoản bị xoá sang tài khoản số 1. Chạy lại cả bốn phép kiểm: tất cả sạch, trang chủ trả 200.

Tóm tắt: dấu vết nào, phép kiểm nào bắt

  • Tệp lõi bị sửa: kiểm 1.
  • Tệp lạ trong thư mục lõi: kiểm 1, nhưng sau khi tải lại lõi chỉ còn là một dòng Warning trước chữ Success.
  • Tệp PHP trong uploads: chỉ kiểm 4.
  • Plugin bị sửa: kiểm 2.
  • Tài khoản quản trị lạ: kiểm 3.

Những gì mình chưa kiểm

  • Chưa đụng mã độc thật, chưa thử plugin bảo mật hay dịch vụ quét nào.
  • Chưa kiểm dấu vết nằm trong cơ sở dữ liệu, ví dụ đoạn mã chèn vào bài viết hay một tuỳ chọn lạ.
  • Chưa kiểm theme, chưa thử Nginx, chưa đo plugin không có trên kho plugin của WordPress.
  • Chưa đo chuyện khôi phục website WordPress bị hack từ bản sao lưu cũ. Ca đó cần chọn bản sao lưu được tạo trước khi site bị xâm nhập, và mình chưa có số liệu cho việc chọn đó.