PHP2Shell (CVE-2026-109618/109619): kiểm tra phiên bản, vá và giảm thiểu

Bản PHP nào đã vá PHP2Shell, cách kiểm tra máy chủ thật sự chạy gì, cấu hình tạm từ advisory, giới hạn của WAF, và CVE-2026-115560.

· Đăng ngày · 8 phút đọc · Phiên bản: PHP 8.2, PHP 8.3, PHP 8.4, PHP 8.5

PHP2Shell là hai lỗ hổng trong chính PHP (CVE-2026-109618 và CVE-2026-109619) cho phép chạy code từ xa mà không cần đăng nhập, và đã bị khai thác trước cả khi bản vá ra ngày 21/10/2026. Máy chủ của bạn có bị ảnh hưởng không, cần lên phiên bản nào, và làm gì khi chưa vá được ngay? Trả lời ngắn: mọi máy chủ web chạy PHP từ 5.4 trở lên đều nằm trong vùng ảnh hưởng, cách sửa duy nhất là lên 8.5.12, 8.4.27, 8.3.36 hoặc 8.2.35, còn các cấu hình tạm chỉ chặn được một phần.

Bài này gom từ advisory của PHP, các GitHub Security Advisory gốc, phân tích của Cloudflare và Recorded Future, và khuyến cáo của Cục An ninh mạng. Bài đi qua: lỗi là gì, cách kiểm tra phiên bản đang chạy, cấu hình giảm thiểu, giới hạn của WAF, lỗi đi kèm CVE-2026-115560 chưa có bản vá, và cần xem log gì. Bức tranh rộng hơn về việc AI làm số lỗ hổng tăng vọt nằm ở bài AI và cơn bão lỗ hổng tháng 10/2026.

PHP2Shell là lỗi bộ nhớ trong PHP, không phải trong code của bạn

Cập nhật WordPress, plugin hay framework không sửa được PHP2Shell, vì lỗi nằm trong runtime PHP. Theo advisory ngày 21/10, có hai lỗi:

  • CVE-2026-109618: khi hết bộ nhớ, PHP có thể bị ngắt giữa lúc dữ liệu nội bộ của request mới khởi tạo một phần, và bước dọn dẹp request sau đó coi dữ liệu dở dang này là hợp lệ.
  • CVE-2026-109619: trạng thái nội bộ thuộc về một request có thể còn sống sau khi vùng nhớ của nó đã bị giải phóng. Một request sau, do cùng worker xử lý, có thể dùng trạng thái cũ đó trước khi nó được khởi tạo lại.

Advisory nói mọi bản cài PHP phục vụ request web đều có rủi ro, gồm PHP-FPM, Apache với mod_php, php-cgi, FrankenPHP và LiteSpeed, và rủi ro cao nhất với mod_php. Cloudflare cho biết lỗi ảnh hưởng mọi máy chủ web chạy PHP 5.4 trở lên. Cả hai lỗi có điểm CVSS v4 là 9,2, nhưng vector trong GHSA-6wmf-4rv5-p3rp ghi độ phức tạp tấn công cao (AC:H): khai thác được, nhưng không dễ như một lỗi SQL injection.

Dòng thời gian: lỗi bị khai thác trước khi có bản vá

Đây là lý do "đợi bản vá rồi tính" không đủ. Theo Recorded Future, thêm Cloudflare cho dòng WAF và php.net cho ngày 23/10:

Thời điểm (UTC) Sự kiện
Đầu 8 Ryan Austin của Calif báo một lỗi cho PHP (theo Dương Ngọc Thái)
24/8 Wiz báo các lỗi họ tìm được cho PHP
20/10 PHP báo trước bản phát hành khẩn cho ngày 21/10
21/10, 02:29 Một gói chứa chi tiết lỗi bị đưa lên VirusTotal
21/10, 03:02 Cloudflare bật luật WAF cho khách hàng mọi gói, kể cả gói miễn phí
21/10, 07:34 Patchstack nhận báo cáo khai thác thật từ đối tác hosting
21/10, 13:52 PHP phát hành bản vá
23/10 PHP công bố CVE-2026-115560 (xem mục bên dưới)

Recorded Future cũng lưu ý: các báo cáo hiện có chưa cho thấy toàn bộ quy mô khai thác thành công. Theo Reuters, PHP Foundation chưa thấy dấu hiệu kẻ tấn công vào được các hệ thống đã vá.

Phiên bản nào đã an toàn

Lên đúng bản vá của nhánh bạn đang dùng. Nhánh 8.1 trở xuống không còn bản phát hành chính thức. Tổng hợp từ advisory của PHP:

Nhánh Bản đã vá Ghi chú
8.5 8.5.12 Thêm fatal_error_backtraces=0 nếu chưa lên được
8.4 8.4.27 —
8.3 8.3.36 —
8.2 8.2.35 Hết hỗ trợ ngày 31/12/2026, nên lên kế hoạch nâng cấp
8.6 (thử nghiệm) 8.6.0 RC4 Mọi bản 8.6.0 trước RC4 cần cập nhật
7.4, 8.0, 8.1 Không có bản phát hành Có bản backport tối thiểu dạng mã nguồn, hoặc bản vá từ distro và nhà cung cấp LTS
7.3 trở xuống Không có Advisory không có backport cho các nhánh này: phải nâng cấp

Bản PHP của distro Linux đi theo kho bảo mật, không phải kho thường. Trên Debian security tracker, gói php8.2 trong kho chính của bookworm vẫn là 8.2.32 (còn lỗi), bản đã vá là 8.2.35-1~deb12u1 trong kho bookworm-security. Nếu máy chủ của bạn không bật kho bảo mật, apt upgrade sẽ không mang bản vá về.

Kiểm tra máy chủ của bạn đang chạy gì

Kiểm tra phiên bản PHP mà web server thật sự dùng, không chỉ bản CLI. Trên cùng một máy, php ở dòng lệnh và PHP-FPM có thể là hai phiên bản khác nhau. Mình không có máy chạy PHP ở chỗ viết bài, nên dưới đây là các lệnh, không kèm output:

php -v          # bản CLI
php-fpm8.2 -v   # bản FPM; tên binary theo distro, ví dụ php-fpm, php-fpm8.3
php-fpm8.2 -i | grep -E 'session.upload_progress.enabled|memory_limit|post_max_size'

Lệnh cuối cho thấy giá trị trong php.ini của bản FPM, nhưng không thấy các giá trị ghi đè trong file pool (php_admin_value, php_value), nên cần đọc cả các file pool.

Với container dùng image PHP chính thức trên Docker Hub, phiên bản nằm trong biến môi trường PHP_VERSION, đặt sẵn trong Dockerfile của image:

docker image inspect <image> --format '{{.Config.Env}}' | tr ' ' '\n' | grep PHP_VERSION

Đừng quên những chỗ ít ai nhớ tới: môi trường staging, container của phần mềm bên thứ ba có nhúng PHP, và các máy chủ cũ không ai quản lý. Bước đầu tiên trong khuyến cáo của Cục An ninh mạng chính là lập danh sách này. Nếu bạn dùng shared hosting hoặc hosting được quản lý, PHP nằm trong tay nhà cung cấp: hỏi họ đã vá chưa.

Chưa vá được ngay: cấu hình giảm thiểu từ advisory

Advisory của PHP đưa ra cấu hình tạm, và tự nói rõ đây không phải bản sửa: "không có biện pháp giảm thiểu đầy đủ, cập nhật là lựa chọn an toàn duy nhất". Advisory liệt kê chúng dạng văn xuôi; mình gom lại thành một khối php.ini. Phần chú thích và giá trị upload_max_filesize là của mình:

; php.ini
memory_limit = -1
post_max_size = 8M          ; 32M if the app needs file uploads
upload_max_filesize = 2M    ; any value below post_max_size
session.upload_progress.enabled = 0
fatal_error_backtraces = 0  ; PHP 8.5 only

Trong pool FPM, cùng các cấu hình này dùng php_admin_value hoặc php_admin_flag (cấu hình PHP-FPM), ứng dụng không ghi đè được:

php_admin_value[memory_limit] = -1
php_admin_flag[session.upload_progress.enabled] = off

Vài điểm advisory nhấn mạnh:

  • Đặt cấu hình ở chỗ áp dụng trước khi request được phân tích: php.ini, pool FPM, hoặc cấu hình server (ví dụ php_admin_value). Không dựa vào ini_set() hay .user.ini.
  • Khởi động lại mọi worker sau khi đổi.
  • memory_limit = -1 nhắm vào CVE-2026-109618. Advisory dặn không thay bằng giới hạn RLIMIT_AS hay RLIMIT_DATA, vì chúng có thể gây đúng lỗi cấp phát bộ nhớ đang bị khai thác. Đổi lại, một request có thể ăn hết RAM, nên đây là đánh đổi tạm thời, không phải cấu hình để lâu. Kiểm tra không có pool, thư mục hay ứng dụng nào đặt lại một giới hạn hữu hạn. Giới hạn bộ nhớ của container hoặc cgroup (memory.max) có thể thay cho giới hạn của PHP, nhưng GHSA-w8hw-w9fx-j79w nói đó cũng không phải biện pháp đầy đủ: nếu một lần cấp phát bộ nhớ ở tầng dưới thất bại, PHP vẫn có thể đi vào đường code có lỗi.
  • session.upload_progress.enabled = 0 chặn các đường khai thác đã xác nhận qua session, nhưng không chặn các biến thể khác. Tắt nó thì thanh tiến trình upload dùng tính năng này sẽ ngừng chạy.

WAF giúp, nhưng chỉ trong điều kiện nhất định

WAF là lớp chặn thêm trong lúc chờ vá, không thay được bản vá. Cloudflare bật luật chặn PHP2Shell từ 03:02 UTC ngày 21/10 cho mọi khách hàng có WAF, kể cả gói miễn phí, nhưng ghi rõ: khách hàng đã đổi session.upload_progress.name khỏi giá trị mặc định thì không được luật này bảo vệ. Khách hàng gói trả phí cần kiểm tra Managed Ruleset đang ở chế độ chặn.

Cục An ninh mạng cũng khuyến nghị bật và cập nhật luật WAF, giới hạn kích thước và số lượng request ở web server hoặc proxy, và kiểm thử kỹ trước khi áp dụng. Một điều kiện hay bị bỏ qua: nếu máy chủ gốc vẫn nhận kết nối trực tiếp từ Internet, kẻ tấn công đi vòng qua WAF được. Recorded Future khuyên chắc chắn máy chủ gốc không truy cập trực tiếp được.

CVE-2026-115560: bản vá ngày 21/10 chưa phải điểm cuối

Ngày 23/10, PHP công bố thêm một lỗi chạy code từ xa mà các bản 21/10 chưa sửa, nhưng điều kiện rất hẹp. Theo advisory thông tin của PHP, ứng dụng phải đặt session.serialize_handler là php_binary hoặc php_serialize trong cấu hình, rồi đổi sang php lúc chạy bằng ini_set() trước khi gọi session_start(), và session upload progress vẫn đang bật.

PHP sẽ sửa lỗi này trong bản phát hành định kỳ tiếp theo và công bố advisory đầy đủ lúc đó. Cho tới lúc ấy, họ khuyên giữ session.upload_progress.enabled=0. Nếu bạn đã tắt nó từ ngày 21/10 cho CVE-2026-109619 thì giữ nguyên tới bản phát hành đó.

Đã vá rồi: vẫn nên xem log từ ngày 20/10

Vá xong chỉ chặn được lần tấn công tiếp theo, không cho biết máy đã bị vào trước đó hay chưa. Vì lỗi bị khai thác trước khi có bản vá, Recorded Future khuyên xem log từ ngày 20/10, và xa hơn nếu được: log của web server, của ứng dụng và dữ liệu từ endpoint. Những dấu hiệu Cục An ninh mạng liệt kê:

  • Request có dung lượng lớn bất thường hoặc tần suất cao.
  • Lỗi hết bộ nhớ lặp lại.
  • Tiến trình PHP dừng đột ngột.
  • File lạ xuất hiện trên máy chủ.

Theo một chuyên gia của GuidePoint được VnExpress dẫn lời, kết quả quét "sạch" không loại trừ khả năng máy đã bị xâm nhập. Nếu thấy dấu hiệu, xử lý như một sự cố thật: cô lập máy, điều tra, và đổi mọi thông tin xác thực có trên máy đó (mật khẩu database, API key, khoá SSH).

Những gì các bước này không giải quyết

Không bước nào trong bài thay được việc lên một nhánh PHP còn được hỗ trợ. Cấu hình tạm chỉ chặn các đường khai thác đã biết. WAF chỉ chặn được mẫu nó nhận ra và chỉ khi traffic đi qua nó. Bản backport cho 7.4, 8.0 và 8.1 là bản tối thiểu, và nhánh 8.2 sẽ hết hỗ trợ sau hai tháng nữa.

PHP2Shell cũng không phải lỗ hổng cuối cùng. Thứ giúp bạn xử lý lỗi tiếp theo nhanh hơn là danh sách những gì đang chạy, cách cập nhật PHP mà không phải làm tay từng máy, và log đủ để trả lời câu hỏi "đã có ai vào chưa".

Tóm tắt

  • PHP2Shell (CVE-2026-109618, CVE-2026-109619) là lỗi bộ nhớ trong runtime PHP 5.4 trở lên, ảnh hưởng mọi cách chạy PHP cho web. Cập nhật plugin không sửa được.
  • Lên 8.5.12, 8.4.27, 8.3.36 hoặc 8.2.35. Bản 8.1 trở xuống không có bản phát hành chính thức. Với distro, kiểm tra kho bảo mật đã bật.
  • Kiểm tra phiên bản PHP-FPM hay mod_php mà web server dùng, không chỉ php -v, và cả container.
  • Chưa vá được: dùng cấu hình tạm trong advisory, đặt trước khi request được phân tích, khởi động lại worker. WAF chỉ là lớp thêm.
  • Giữ session.upload_progress.enabled=0 tới bản sửa CVE-2026-115560, và xem log từ ngày 20/10.

Nếu bạn đã vá PHP2Shell trên nhiều máy chủ và gặp chỗ vướng mà bài chưa nhắc tới, mình rất muốn được trao đổi. Email của mình ở trang chủ.