# Quét mã độc

> Quét tài khoản hosting tìm webshell, backdoor và mã bị chèn, cách ly hoặc bỏ qua kết quả, khôi phục file và xử lý website bị hack theo từng bước.

Source: https://zopanel.net/vi/docs/malware-scan  
Updated: 2026-10-09

**Quét mã độc** kiểm tra file website của các tài khoản hosting để tìm webshell, backdoor, mã PHP bị làm rối và JavaScript bị chèn. Mọi tài khoản được quét tự động mỗi tuần một lần, và quản trị viên, đại lý hay khách hàng đều có thể chạy quét bất cứ lúc nào. File bị phát hiện có thể chuyển vào khu cách ly mà tài khoản không chạm tới được, hoặc đánh dấu là nhận diện nhầm.

## Ai dùng được

| Vai trò | Thấy và làm được gì |
| --- | --- |
| Quản trị viên | Mọi tài khoản. Quét một hoặc tất cả tài khoản, cách ly, bỏ qua vĩnh viễn. |
| Đại lý | Tài khoản của khách mình. Quét, cách ly, bỏ qua (trạng thái **Khách đã bỏ qua**). |
| Khách hàng | Tài khoản của chính mình. Quét, cách ly, bỏ qua (trạng thái **Khách đã bỏ qua**). |

Gói hosting có thể không bao gồm tính năng này: bỏ chọn **Quét mã độc** trong **Tính năng** ở **Gói hosting**. Khi đó khách dùng gói không mở được trang và API của tính năng, nhưng quản trị viên hoặc đại lý vẫn quét được tài khoản của họ. Quản trị viên giới hạn cần được cấp vùng **Bảo mật**.

## Những gì được quét

Trình quét đọc các file trong thư mục `domains/` ở home của từng tài khoản (mọi website của tài khoản) và đối chiếu với bộ chữ ký:

- **Loại file:** `.php`, `.phtml`, `.php3`, `.php4`, `.php5`, `.php7`, `.phar`, `.inc`, `.suspected`, `.js`, `.html` và `.htm`. File JavaScript và HTML chỉ được kiểm tra JavaScript bị chèn và chuỗi hexa dài.
- **Kích thước:** file tối đa 4 MB.
- **Bỏ qua:** `node_modules`, `.git` và bản sao Git của ứng dụng deploy (`repo`). Với ứng dụng deploy, chỉ bản release đang chạy được quét, không quét các bản cũ.
- **Quyền sở hữu:** chỉ file thường thuộc về tài khoản. Không đi theo symbolic link, không đọc hard link trỏ tới file của tài khoản khác hoặc của root.

Database, hộp thư, bản sao lưu và file ngoài `domains/` (ví dụ `~/tmp`) không được quét.

### Các loại phát hiện

| Phát hiện | Mức độ | Khớp với |
| --- | --- | --- |
| **eval mã hoá** | Cao | `eval` hoặc `assert` của `base64_decode`, `gzinflate`, `str_rot13` và tương tự |
| **eval dữ liệu người dùng** | Cao | `eval`, `assert` hoặc `create_function` trên `$_POST`, `$_GET`, `$_REQUEST`, `$_COOKIE` hoặc header HTTP |
| **Thực thi lệnh hệ thống** | Cao | `system`, `exec`, `shell_exec`, `passthru`, `popen`, `proc_open` trên dữ liệu request |
| **Thực thi shell** | Cao | Dấu backtick bao quanh dữ liệu request |
| **Gọi hàm động** | Cao | Tên hàm lấy từ dữ liệu request, gọi với dữ liệu request |
| **Webshell đã biết** | Cao | Dấu hiệu của các shell quen thuộc như FilesMan, WSO, c99, r57, b374k, IndoXploit, AnonymousFox, ALFA |
| **preg_replace /e** | Trung bình | `preg_replace` với modifier `/e` trên dữ liệu request |
| **Trình upload file** | Trung bình | `move_uploaded_file` điều khiển bởi dữ liệu request |
| **Ghi dữ liệu người dùng ra file** | Trung bình | `file_put_contents`, `fwrite` hoặc `fputs` ghi dữ liệu request |
| **Mã bị làm rối (chr)** | Trung bình | Chuỗi dài các lời gọi `chr()` |
| **Mã bị làm rối (hex)** | Trung bình | Chuỗi `\x..` dài giải mã ra văn bản đọc được (trừ `vendor/` và `wp-includes/`) |
| **Payload mã hoá lớn** | Trung bình | `eval`, `assert` hoặc `base64_decode` của chuỗi base64 từ 1.000 ký tự |
| **Chèn JavaScript** | Trung bình | `document.write(unescape(...))` ghi ra script hoặc iframe, hoặc chuỗi `String.fromCharCode` dài |
| **File PHP trong thư mục uploads** | Trung bình | File PHP có mã nằm trong thư mục `uploads` (kể cả `wp-content/uploads`) |

Một số mẫu hợp lệ được lọc bỏ: chuỗi hexa giải mã ra bảng dữ liệu nhị phân, `document.write(unescape(...))` không nạp script hay iframe bên ngoài, và các file chỉ có comment như `<?php // Silence is golden.` của WordPress.

## Chạy quét

1. Mở **Quét mã độc**.
2. Quản trị viên và đại lý chọn một tài khoản trong ô chọn tài khoản, hoặc chọn tất cả.
3. Bấm **Quét ngay**. Log tác vụ liệt kê từng tài khoản, số file đã kiểm tra, từng phát hiện, và kết thúc bằng dòng như `Done: 5230 files, 2 findings in 14.2s`.

Trình quét dùng một phần tư số nhân CPU của server (từ 1 đến 8), nên website vẫn phản hồi bình thường trong lúc quét.

### Quét hằng tuần

Mỗi Chủ nhật lúc 03:00 (giờ server), ZoPanel tự quét tất cả tài khoản hosting. Lịch này không thay đổi được; bấm **Quét ngay** khi cần quét thêm.

## Xem kết quả

Trang hiển thị ba bộ đếm (**Cần xử lý**, **Mức nguy hiểm cao**, **Đã cách ly**) và bảng, mỗi dòng một phát hiện:

- **File**: đường dẫn tính từ home của tài khoản kèm số dòng, bên dưới là dòng mã bị khớp.
- **Chủ sở hữu** (quản trị viên và đại lý): tài khoản chứa file.
- **Phát hiện**: quy tắc, tô màu theo mức độ, và ngày phát hiện lần đầu.
- **Trạng thái**: **Cần xử lý**, **Đã cách ly**, **Khách đã bỏ qua** hoặc **Đã bỏ qua**.

Mở file bằng [Quản lý file](/vi/docs/file-manager) hoặc SFTP để xem trước khi xử lý. Phát hiện chưa xử lý, kể cả loại khách đã bỏ qua, làm giảm điểm trong **Trung tâm bảo mật** và hiện trên dashboard.

Khi tài khoản được quét lại:

- phát hiện **Cần xử lý** mà file đã mất hoặc không còn khớp sẽ bị xoá khỏi danh sách;
- phát hiện **Đã cách ly** chuyển lại thành **Cần xử lý** nếu cùng file đó lại khớp (file được đặt lại, hoặc kẻ tấn công tạo lại);
- phát hiện **Đã bỏ qua** giữ nguyên trạng thái.

## Cách ly file

1. Bấm **Cách ly** trên phát hiện và xác nhận.
2. File được chuyển khỏi website vào `/var/lib/zopanel/quarantine/<tài-khoản>/` trên server. Chỉ root đọc được thư mục này: tài khoản, và cả kẻ đã xâm nhập tài khoản, không chạy, khôi phục hay xoá được file nữa.

Bản cách ly được đặt tên theo thời điểm và đường dẫn gốc, ví dụ `20261012-031502_a1b2c3d4_domains__example.com__public_html__wp-content__uploads__x.php`.

**Lưu ý:** Nếu file là hợp lệ, website có thể lỗi ở chỗ dùng file đó. Hãy kiểm tra website sau khi cách ly và khôi phục file nếu cần.

### Khôi phục file đã cách ly

Không có nút khôi phục. Quản trị viên khôi phục qua SSH bằng quyền root:

```bash
# Liệt kê file đã cách ly của tài khoản
ls -l /var/lib/zopanel/quarantine/USER/

# Đặt lại một file, chủ sở hữu là tài khoản
install -m 0640 -o USER -g www-data \
  /var/lib/zopanel/quarantine/USER/20261012-031502_a1b2c3d4_domains__example.com__public_html__file.php \
  /home/USER/domains/example.com/public_html/file.php
```

Lần quét sau sẽ phát hiện lại file và chuyển phát hiện về **Cần xử lý**. Nếu đó là nhận diện nhầm, lúc này hãy bấm **Bỏ qua**.

## Bỏ qua nhận diện nhầm

Bấm **Bỏ qua** trên phát hiện.

- Khi **quản trị viên** bỏ qua, trạng thái là **Đã bỏ qua** và phát hiện không còn được tính ở đâu nữa.
- Khi **khách hàng hoặc đại lý** bỏ qua, trạng thái là **Khách đã bỏ qua**. Phát hiện vẫn được tính trong **Trung tâm bảo mật** và trên dashboard, và quản trị viên vẫn thấy nút **Cách ly**, **Bỏ qua**, nên kẻ chiếm được tài khoản khách không giấu được backdoor.

Các trường hợp nhận diện nhầm hay gặp: plugin bảo mật, sao lưu, quản lý file dùng `eval` hoặc ghi file upload một cách hợp lệ; thư viện đã minify chứa dữ liệu mã hoá; file PHP mà plugin để trong thư mục con riêng của `uploads`. Nếu file thuộc một plugin quen thuộc, hãy so với bản tải mới cùng phiên bản trước khi bỏ qua.

## Sau khi bị nhiễm mã độc

Webshell chỉ là triệu chứng: kẻ tấn công đã vào qua một lỗ hổng khác. Cách ly file là bước đầu, chưa phải bước cuối.

1. **Cách ly mọi phát hiện mức cao** của tài khoản, sau đó xem các phát hiện mức trung bình.
2. **Website WordPress:** ở tab WordPress của website, chạy **Kiểm tra toàn vẹn file** để tìm file lõi và plugin bị sửa, cập nhật toàn bộ bằng **Cập nhật tất cả**, xoá plugin và theme không dùng, rồi **Đổi khoá bảo mật** (đăng xuất mọi người) và dùng **Đặt lại mật khẩu** cho tài khoản quản trị. Bấm **Áp dụng tất cả** trong thẻ **Bảo mật**. Xem [WordPress](/vi/docs/wordpress).
3. **Đổi mật khẩu** tài khoản hosting, các tài khoản SFTP/FTP và user database, sau đó cập nhật mật khẩu database mới vào cấu hình ứng dụng.
4. **Tìm cửa hậu còn sót:** [cron job](/vi/docs/cron-jobs) lạ, SSH key lạ, và tài khoản quản trị mới trong ứng dụng.
5. **Nếu không chắc chắn, hãy khôi phục** file và database từ bản sao lưu trước thời điểm bị nhiễm. Xem [Sao lưu](/vi/docs/backups).
6. **Bật tường lửa ứng dụng web (WAF)** cho website trong tab **Công cụ**. Xem [Bảo mật](/vi/docs/security).
7. **Kiểm tra mail gửi ra:** website bị hack thường gửi spam. Xem hàng đợi mail và giới hạn gửi trong [Email](/vi/docs/email).
8. **Bấm Quét ngay lần nữa** cho tới khi không còn phát hiện nào cần xử lý.

## Thông báo

- **Quản trị viên:** sự kiện **Phát hiện mã độc** trong **Cài đặt → Cảnh báo** (email, Telegram hoặc webhook), báo số phát hiện **Cần xử lý** và **Khách đã bỏ qua** trong các tài khoản được quét. Xem [Cài đặt panel](/vi/docs/panel-settings).
- **Khách hàng và đại lý:** **Phát hiện file đáng ngờ** trong **Tài khoản của tôi → Thông báo**, qua email hoặc Telegram, kèm số phát hiện còn **Cần xử lý** trong tài khoản của chính họ.

Thông báo được xét sau mỗi lần quét, kể cả lần quét hằng tuần. Phát hiện **Đã cách ly** hoặc **Đã bỏ qua** bởi quản trị viên không gây thông báo nữa, và phát hiện khách đã bỏ qua không còn báo cho khách.

## Xử lý sự cố

| Thông báo hoặc hiện tượng | Nguyên nhân và cách xử lý |
| --- | --- |
| "Không phát hiện mối nguy" ngay sau khi cài | Chưa chạy lần quét nào, hoặc không có gì khớp. Bấm **Quét ngay**. |
| Cách ly lỗi với `mv: cannot stat …` | File đã bị chuyển hoặc xoá. Bấm **Quét ngay** để làm mới danh sách. |
| "the file does not belong to the account" | File thuộc user khác (ví dụ root). Kiểm tra bằng quyền root trên server; panel chỉ cách ly file của chính tài khoản. |
| "invalid path" | Phát hiện trỏ ra ngoài `domains/`. Quét lại tài khoản. |
| File biết chắc bị nhiễm nhưng không được báo | File có thể lớn hơn 4 MB, có đuôi khác (ví dụ file `.jpg` chứa mã PHP), nằm ngoài `domains/`, hoặc dùng kỹ thuật mà bộ chữ ký chưa bao phủ. Kiểm tra thủ công và khôi phục từ bản sao lưu sạch. |
| Website lỗi sau khi cách ly | File đó cần thiết. Khôi phục (xem ở trên) và bỏ qua phát hiện nếu file sạch. |

## Xem thêm

- [Bảo mật](/vi/docs/security)
- [WordPress](/vi/docs/wordpress)
- [Sao lưu](/vi/docs/backups)
- [Quản lý file](/vi/docs/file-manager)
- [Cài đặt panel: cảnh báo](/vi/docs/panel-settings)
- [WordPress: FAQ My site was hacked](https://wordpress.org/documentation/article/faq-my-site-was-hacked/)
