Hôm qua mình lướt qua bản tin bảo mật của Patchstack thì thấy một cái khiến mình ngồi dặn lòng hẳn: plugin GiveWP — plugin gây quỹ phổ biến nhất nhì WordPress với hơn 100.000 site đang dùng — vừa bị phát hiện lỗ hổng cho phép kẻ tấn công chạy mã tùy ý trên server, điểm CVSS 10.0/10, mức nghiêm trọng nhất thang đo. Điều đáng nói là ở phiên bản cũ, một cài đặt mặc định không cần chỉnh gì cũng dính. Trong bài này mình sẽ giải thích lỗ hổng hoạt động ra sao và hướng dẫn bạn từng bước kiểm tra, cập nhật và rà soát site xem có bị khai thác hay không.
Lỗ hổng GiveWP này nghiêm trọng đến mức nào?

Đây là chuỗi khai thác đi từ PHP Object Injection (không cần đăng nhập) lên Remote Code Execution — tức kẻ tấn công chạy được lệnh tùy ý trên server của bạn. Với phiên bản 4.16.5.1 trở xuống, chỉ cần có một donation form đã publish và một payment gateway đang bật (cài mặc định đã có) là đủ điều kiện khai thác. Không cần bật Test Mode, không cần debug, không cần quản trị viên làm gì sai cả. Từ 4.16.6 đến 4.16.7.1 phạm vi hẹp hơn nhưng vẫn khai thác được nếu site từng nâng cấp từ bản cũ hoặc dùng “Option-Based Form Editor”. Nếu site bạn chạy GiveWP, hãy coi đây là việc cần xử lý trong hôm nay, không phải cuối tuần.
Chuỗi khai thác hoạt động như thế nào?
Điểm thú vị về mặt kỹ thuật ở đây là cách nó vượt qua “hàng rào” an toàn. GiveWP có một hàm safeUnserialize() gọi unserialize() với allowed_classes => false để chặn object injection. Nhưng cờ này không xóa object đi — nó biến object thành __PHP_Incomplete_Class, giữ nguyên tên class và thuộc tính. Khi dữ liệu này được serialize lại vào bảng wp_give_sessions, PHP ghi ra đúng những byte gốc của kẻ tấn công. Lần đọc kế tiếp không còn lớp guard ấy, gadget object “sống dậy” thật. Kẻ tấn công cắm payload vào trường last_name của tài khoản qua profile, rồi quy trình donate kéo nó từ database ra xử lý — nên validation phía request hoàn toàn không thấy. Phần cuối chuỗi là gadget chain từ thư viện TCPDF và TestData mà GiveWP tự ship trong code.
Cách kiểm tra site có đang bị ảnh hưởng không?
Bạn làm theo 3 bước sau là xong. Bước 1: đăng nhập wp-admin, vào Plugins, tìm GiveWP và nhìn cột Version. Bước 2: mở terminal (nếu bạn có SSH) và chạy lệnh WP-CLI cho chính xác:
sudo -u www-data wp --path=/var/www/thienlv.com/public_html plugin list | grep giveBước 3: đối chiếu kết quả. Bản 4.16.7.1 và mọi phiên bản cũ hơn đều bị ảnh hưởng. Riêng lưu ý: nếu site bạn từng chạy bản GiveWP cũ rồi nâng cấp lên 4.16.6–4.16.7.1, đừng chủ quan — một form bất kỳ thiếu formBuilderSettings (kể cả dạng draft hay trash) là đủ kích hoạt lại toàn bộ chuỗi. Lưu ý: đừng bỏ qua bước 3, nhiều bạn nhìn thấy số phiên bản mới tưởng là an toàn rồi đóng tab.
Cách cập nhật và khắc phục cụ thể thế nào?
Việc khắc phục chính là nâng cấp plugin lên bản mới nhất mà nhà phát triển đã vá. Quy trình an toàn gồm 5 bước:
- Sao lưu toàn bộ site — cả file lẫn database. Đừng bao giờ update plugin gây quỹ khi chưa có backup, vì dữ liệu donation là dữ liệu tiền bạc.
- Chạy lệnh cập nhật:
sudo -u www-data wp plugin update give --path=/var/www/thienlv.com/public_html(hoặc update trực tiếp trong wp-admin). - Sau khi update, kiểm tra lại một lượt donation form và payment gateway xem hoạt động bình thường, đặc biệt nếu bạn dùng payment gateway bên thứ ba.
- Nếu bạn dùng dịch vụ như Patchstack hoặc Wordfence, cập nhật rules — Patchstack đã phát hành mitigation rule cho lỗ hổng này.
- Kiểm tra và xóa các tài khoản donor không rõ nguồn gốc (xem phần rà soát bên dưới).
Cách rà soát xem site đã bị khai thác chưa?
Vì payload cắm vào trường last_name của user meta rồi nằm trong wp_give_sessions, bạn nên soi hai nơi này. Chạy hai truy vấn sau qua WP-CLI hoặc phpMyAdmin:
sudo -u www-data wp db query "SELECT user_id, meta_value FROM wp_usermeta WHERE meta_key='last_name' AND meta_value LIKE 'a:1:%' OR meta_key='last_name' AND meta_value LIKE 'O:%'"
sudo -u www-data wp db query "SELECT session_key FROM wp_give_sessions LIMIT 20"Nếu thấy giá trị last_name bắt đầu bằng O: (định dạng object của PHP serialize) thay vì tên họ thông thường, đó là dấu hiệu đáng ngờ nặng. Tiếp đó, tìm thêm dấu vết hậu khai thác: file PHP lạ trong thư mục wp-content/uploads/, tài khoản admin mới xuất hiện không rõ nguồn gốc, và log truy cập có các request bất thường tới endpoint donate từ cùng một IP lặp liên tục.
Làm sao để phòng tránh các lỗ hổng tương tự?
Ba thói quen mình áp dụng trên VPS của chính mình: thứ nhất, bật auto-update cho plugin và kiểm tra email bảo mật hàng sáng — tin CVE trễ một ngày là rủi ro thêm một ngày. Thứ hai, đặt disable file edit và chặn chạy PHP trong uploads ở tầng web server, vì đa số hậu khai thác RCE đều dừng lại ở việc nhét backdoor file vào uploads. Với Nginx bạn thêm vào block tương ứng:
location ~* /wp-content/uploads/.*\.php$ { deny all; }Thứ ba, hạn chế số plugin tối thiểu và gỡ hẳn những plugin không dùng — code không tồn tại thì không thể có gadget chain. Lỗ hổng lần này của GiveWP một lần nữa cho thấy điểm yếu unserialize của PHP vẫn là mỏ vàng cho attacker, kể cả khi nhà phát triển đã cố “wrap” cho an toàn.
Kết luận
CVSS 10.0, không cần xác thực, khai thác được trên cài đặt mặc định — cả ba yếu tố này cùng lúc là điều hiếm gặp. Nếu bạn quản lý site từ thiện hay tổ chức phi lợi nhuận đang chạy GiveWP, hãy khóa cổng ngay hôm nay: backup, update, rà soát sessions và user meta theo hướng dẫn trên. Mình từng xử lý vài site bị deface chỉ vì chủ site lơ là plugin gây quỹ đúng một tuần, và việc dọn dẹp sau vụ attaker có RCE luôn tốn gấp mười lần công phòng tránh trước. Nếu bạn gặp lỗi khi update hoặc thấy dấu hiệu đáng ngờ trong database, cứ để lại comment, mình sẽ cùng bạn soi từng bước.