Logo
Featured Image

PHP2Shell: 2 lỗ hổng RCE nghiêm trọng CVE-2026-109618 & CVE-2026-109619 — Kiểm tra và vá ngay trước 29/10

Author
Tobi • 28/10/2026 • 6 views

1. Chuyện gì đang xảy ra với PHP?

Nếu bạn đang chạy website bằng PHP — WordPress, Laravel, hay bất kỳ mã nguồn nào khác — thì tuần này có một việc cần làm ngay, không để cuối tuần: kiểm tra phiên bản PHP trên server và vá lên bản mới nhất.

Ngày 21/10/2026, PHP Group phát hành bản vá khẩn cho hai lỗ hổng nghiêm trọng trong chính nhân PHP, gọi chung là PHP2Shell: CVE-2026-109618 và CVE-2026-109619. Cả hai đều cho phép kẻ tấn công chạy mã từ xa mà không cần đăng nhập (RCE), đều được chấm CVSS 4.0: 9.2/10 (Critical).

Điểm đáng sợ nhất: lỗi nằm ở tầng xử lý request của PHP, tức là nó chạy trước cả code ứng dụng của bạn. WordPress của bạn có cập nhật đầy đủ, plugin bảo mật có mạnh đến đâu cũng không cứu được — vì request độc hại đã chạm tới lỗi trước khi ứng dụng kịp làm gì.

Và đây không còn là nguy cơ lý thuyết. Ngày 26/10/2026, Cơ quan An ninh mạng Hoa Kỳ (CISA) đã đưa cả hai CVE vào danh mục Known Exploited Vulnerabilities (KEV) — tức là đã có bằng chứng khai thác thực tế ngoài đời thực — và yêu cầu các cơ quan liên bang Mỹ khắc phục trước 29/10/2026. Bạn không thuộc diện bị CISA bắt buộc, nhưng mốc 29/10 là một thước đo tốt cho mức độ khẩn cấp: nếu người ta cho cả một bộ máy liên bang chỉ 3 ngày, thì server của bạn cũng không nên chờ lâu hơn thế.

2. PHP2Shell là gì? Hai lỗ hổng hoạt động ra sao?

Giải thích ngắn gọn, không cần đọc code C:

2.1. CVE-2026-109618 — RCE qua lỗi xử lý hết bộ nhớ (OOM corruption)

Khi một request làm PHP cạn bộ nhớ giữa chừng (ví dụ qua body multipart/form-data được chế tạo đặc biệt), PHP sẽ ngắt request bằng cơ chế longjmp(). Vấn đề là lúc bị ngắt, dữ liệu request mới chỉ được khởi tạo một nửa — nhưng bước dọn dẹp cuối request lại xử lý chỗ dữ liệu dở dang đó như thể nó hợp lệ. Kẻ tấn công lợi dụng sự không nhất quán này để làm hỏng bộ nhớ và cuối cùng chạy được mã tùy ý.

2.2. CVE-2026-109619 — RCE qua trạng thái request cũ còn sót lại (stale global state)

Một số trạng thái nội bộ của PHP gắn với từng request, nhưng trong một số tình huống (ví dụ request bị lỗi nghiêm trọng, timeout) trạng thái đó không được dọn sạch. Request tiếp theo do cùng một worker xử lý có thể đọc phải vùng nhớ đã được giải phóng (use-after-free) và bị lái sang chạy mã của kẻ tấn công. Một trong các đường dẫn đã được xác nhận đi qua tính năng session.upload_progress — tính năng này mặc định bật từ PHP 5.4.

Điểm chung của cả hai: kẻ tấn công không cần tài khoản, không cần biết bạn dùng CMS hay framework gì. Chỉ cần server của bạn nhận request web bằng PHP là đủ điều kiện.

3. Ai bị ảnh hưởng?

Phạm vi ảnh hưởng rất rộng, vì lỗi nằm trong nhân PHP chứ không nằm trong một ứng dụng cụ thể:

  • Mọi phiên bản từ PHP 5.4.0 trở lên mà chưa cập nhật lên bản vá (xem bảng dưới).
  • Mọi cách chạy PHP phục vụ web: Apache mod_php, PHP-FPM, php-cgi, FrankenPHP, LiteSpeed. Trong đó PHP Group đánh giá mod_php là rủi ro cao nhất, vì đã có PoC chứng minh khai thác được trước khi code ứng dụng chạy.
  • Mọi ứng dụng chạy trên PHP: WordPress, Drupal, Joomla, Magento, Laravel, Symfony... — cập nhật ứng dụng không vá được lỗi này, chỉ cập nhật PHP mới vá được.

Minh họa isometric máy chủ PHP được bảo vệ bởi lá chắn bảo mật

Riêng PHP 8.1 trở xuống đã hết hỗ trợ: PHP Group không phát hành bản vá chính thức cho các nhánh này, chỉ có bản backport nguồn tối thiểu cho 7.4, 8.0 và 8.1 dành cho người tự build từ source. Một số nhà phân phối (distro) và nhà cung cấp LTS có gói đã backport riêng. Nếu bạn còn ở nhánh hết hỗ trợ, đây chính là lúc phải lên kế hoạch nâng cấp nhánh — CISA thậm chí khuyến cáo đưa hệ thống PHP không vá được ngoại tuyến (offline) cho đến khi vá xong.

4. Mức độ nghiêm trọng: bằng chứng khai thác thực tế

Minh họa isometric cập nhật và vá lỗi máy chủ

  • 17/10: Amazon Threat Intelligence ghi nhận lượt tấn công thử nghiệm đầu tiên — tức là kẻ xấu đã ra tay trước cả khi bản vá tồn tại.
  • 20/10: Chi tiết kỹ thuật bị rò rỉ sớm, phá vỡ lịch công bố phối hợp dự kiến ngày 22/10.
  • 21/10: PHP Group phát hành bản vá khẩn: 8.5.12, 8.4.27, 8.3.36, 8.2.35. Cloudflare ghi nhận hàng triệu lượt tấn công thử nghiệm trong ngày.
  • 24/10: Nghiên cứu bảo mật xác nhận RCE thành công trên honeypot chạy PHP 8.4.26 chưa vá.
  • 26/10: CISA đưa cả hai CVE vào danh mục KEV, hạn khắc phục 29/10 cho các cơ quan liên bang Mỹ.

Một lưu ý quan trọng: không có cách vá tạm hoàn chỉnh. PHP Group nói rõ cập nhật là cách khắc phục đầy đủ duy nhất. Các biện pháp như tắt session.upload_progress hay bật rule WAF chỉ giảm bề mặt tấn công trong lúc chờ vá — chúng mua thời gian, không thay thế bản vá.

5. Cách kiểm tra server của bạn trong 2 phút

SSH vào server (VPS, máy chủ riêng) và chạy các lệnh sau. Mình đã chạy thử toàn bộ lệnh trong bài này trên một máy Ubuntu 24.04 sạch để bạn thấy kết quả thật trông như thế nào.

5.1. Xem phiên bản PHP đang chạy

php -v cho biết phiên bản CLI. Nhưng quan trọng hơn là phiên bản mà web server thực sự đang dùng — vì CLI và PHP-FPM có thể khác nhau. Kiểm tra cả hai:

php -v php-fpm -v 2>/dev/null || php-fpm8.3 -v 2>/dev/null || echo "Chua cai php-fpm hoac ten dich vu khac" php -r 'echo "PHP_VERSION: ", PHP_VERSION, PHP_EOL;'

Đối chiếu kết quả với bảng ở mục 3. Nếu số phiên bản của bạn thấp hơn bản vá của nhánh đó — ví dụ đang ở 8.3.35 trở xuống — là bạn đang bị ảnh hưởng.

5.2. Chạy script kiểm tra tự động

Để khỏi tra bảng bằng tay, bạn có thể lưu đoạn script sau thành kiem-tra-php.php rồi chạy php kiem-tra-php.php. Script chỉ đọc phiên bản hiện tại và đối chiếu với bảng bản vá của PHP Group, không gửi gì ra ngoài:

<?php $fixed = ['8.2' => '8.2.35', '8.3' => '8.3.36', '8.4' => '8.4.27', '8.5' => '8.5.12']; [$major, $minor] = explode('.', PHP_VERSION, 3); $branch = "$major.$minor"; if (!isset($fixed[$branch])) { echo "CANH BAO: PHP " . PHP_VERSION . " thuoc nhanh het ho tro (8.1 tro xuong). "; echo "Khong co ban va chinh thuc - can nang cap nhanh.\n"; } elseif (version_compare(PHP_VERSION, $fixed[$branch], '>=')) { echo "OK: PHP " . PHP_VERSION . " da dat ban va " . $fixed[$branch] . ".\n"; } else { echo "CHUA VA: PHP " . PHP_VERSION . " - can cap nhat len " . $fixed[$branch] . ".\n"; }

Ảnh terminal chạy lệnh php -v và script kiểm tra phiên bản PHP trên máy Ubuntu giả lập

Trong lần chạy thử của mình, máy Ubuntu 24.04 cài PHP 8.3 từ kho mặc định và script báo "CHƯA VÁ" theo số phiên bản của PHP Group. Đây chính là trường hợp bạn cần lưu ý ở mục 5.4: gói của distro có thể đã backport bản vá nhưng giữ nguyên số phiên bản, nên đừng chỉ nhìn số phiên bản mà kết luận vội.

5.3. Kiểm tra session.upload_progress và các PHP đang cài

php -i | grep -i upload_progress dpkg -l | grep php

Ảnh terminal kiểm tra cấu hình session.upload_progress và danh sách gói PHP đã cài

Nếu session.upload_progress.enabled đang là On và bạn chưa vá được ngay, hãy tắt tạm nó (xem mục 6.4) — đây là một trong các đường dẫn khai thác đã xác nhận của CVE-2026-109619.

5.4. Trường hợp dùng gói của distro: kiểm tra backport

Ubuntu, Debian, AlmaLinux... thường backport bản vá bảo mật vào gói cũ mà không đổi số phiên bản PHP. Ví dụ gói php8.3 của Ubuntu có thể đã chứa bản vá dù php -v vẫn hiện 8.3.6. Cách kiểm tra chắc chắn nhất:

apt changelog php8.3 2>/dev/null | head -40 # hoac tra CVE tracker cua distro, vi du Ubuntu: # https://ubuntu.com/security/CVE-2026-109618

Nếu changelog ghi rõ đã vá CVE-2026-109618/109619 thì bạn đã an toàn dù số phiên bản trông có vẻ cũ. Nếu không thấy, hãy coi như chưa vá và làm theo mục 6.

5.5. Đừng quên các PHP "ẩn"

Nhiều server có hơn một PHP: PHP của hệ thống, PHP của panel (cPanel, Plesk, DirectAdmin...), PHP đóng gói trong appliance, container Docker cũ. Hãy rà soát cả:

which -a php; ls /usr/bin/php* 2>/dev/null docker ps --format '{{.Names}} {{.Image}}' 2>/dev/null | head -20

Với Docker, chỉ cần image base dùng PHP cũ là đủ rủi ro — kiểm tra tag image và rebuild với image đã vá.

6. Cách vá từng bước

6.1. Ubuntu / Debian (dùng kho chính thức hoặc PPA Ondřej Surý)

sudo apt update sudo apt install --only-upgrade php8.3 php8.3-fpm # neu ban dung PPA ondrej/php, ban va se co trong kho PPA sau khi duoc dong goi sudo systemctl restart php8.3-fpm apache2 2>/dev/null || sudo systemctl restart php8.3-fpm php -v && php-fpm8.3 -v

Bắt buộc restart PHP-FPM/Apache sau khi cập nhật. Worker cũ vẫn chạy binary cũ trong bộ nhớ là cách phổ biến nhất khiến server "đã vá mà vẫn dính". Kiểm tra lại bằng php-fpm -v sau khi restart, đừng chỉ tin vào kết quả apt.

6.2. AlmaLinux / RHEL / CentOS Stream (Remi)

sudo dnf update php\* sudo systemctl restart php-fpm httpd php -v

6.3. Docker

Đổi tag image sang bản đã vá (ví dụ php:8.3.36-fpm hoặc mới hơn), rebuild và deploy lại. Nhớ kiểm tra cả image của các service phụ dùng PHP, không chỉ app chính.

6.4. Chưa vá được ngay thì làm gì?

  • Tắt session.upload_progress tạm thời: thêm session.upload_progress.enabled=0 vào php.ini rồi restart PHP. Việc này chỉ bịt một đường dẫn của CVE-2026-109619, không vá được CVE-2026-109618.
  • Bật rule WAF: Cloudflare đã bật rule chặn PHP2Shell cho mọi gói (kể cả miễn phí). Nếu bạn dùng WAF khác, kiểm tra xem nhà cung cấp đã có rule chưa. Rule WAF mua thời gian, không thay thế bản vá — và kẻ tấn công luôn tìm cách lách rule.
  • Hạn chế truy cập: nếu được, chỉ cho phép IP tin cậy truy cập trang quản trị và các endpoint upload trong lúc chờ vá.
  • Với PHP 8.1 trở xuống: lên lịch nâng cấp nhánh ngay. Trong lúc chờ, cân nhắc đưa hệ thống ra khỏi Internet nếu dữ liệu trên đó quan trọng — đúng như khuyến cáo của CISA.

Lưu ý thêm: ngày 23/10, PHP tiếp tục ra khuyến cáo liên quan đến session.upload_progress (CVE-2026-115560) — một lý do nữa để tắt tính năng này nếu bạn chưa vá được ngay.

7. Sau khi vá: kiểm tra xem server đã từng bị xâm nhập chưa

Vá xong không có nghĩa là xong việc — nếu server của bạn từng chạy PHP chưa vá trong khoảng thời gian từ 17/10 đến nay, kẻ tấn công có thể đã kịp để lại "cửa hậu". Hãy rà soát:

  • File lạ trong web root: file PHP mới xuất hiện, file có tên lạ, file bị sửa đổi gần đây mà bạn không đụng tới. So sánh với bản backup sạch hoặc mã nguồn trên git (git status trong thư mục code sẽ lộ ngay file lạ).
  • Cron job mới: crontab -l và ls /etc/cron* — webshell thường tự tạo cron để sống sót sau reboot.
  • Log bất thường: tìm chuỗi Allowed memory size exhausted dày đặc trong log PHP-FPM — đó là dấu vết của các request thăm dò PHP2Shell. Đối chiếu với log truy cập web cùng thời điểm.
  • Process và kết nối lạ: ps aux và ss -tulpn xem có process hay port nghe lạ nào không.

Nếu phát hiện dấu hiệu xâm nhập, đừng chỉ xóa file lạ rồi thôi: webshell thường đi theo cặp, và cách an toàn nhất là khôi phục từ backup sạch trước thời điểm bị tấn công, đổi toàn bộ mật khẩu/khóa liên quan, rồi mới đưa server trở lại.

8. Kết luận

PHP2Shell là trường hợp hiếm mà mức độ khẩn cấp không hề bị thổi phồng: lỗi ở nhân PHP, khai thác không cần đăng nhập, đã có bằng chứng khai thác thực tế, và CISA đã gắn hạn 29/10. May mắn là cách xử lý cũng rất rõ ràng — kiểm tra phiên bản, cập nhật PHP, restart worker, kiểm tra lại. Toàn bộ quy trình với một server chỉ mất vài phút.

Việc cần làm ngay hôm nay: SSH vào từng server chạy PHP của bạn, chạy 3 lệnh ở mục 5, và nếu chưa vá thì vá luôn trong hôm nay. Đừng để một việc vài phút biến thành một sự cố vài tuần.

9. FAQ — Câu hỏi thường gặp

9.1. Cập nhật WordPress/plugin có vá được PHP2Shell không?

Không. Lỗi nằm trong nhân PHP, nằm dưới mọi ứng dụng. Bạn vẫn nên cập nhật ứng dụng thường xuyên, nhưng riêng vụ này chỉ cập nhật PHP mới có tác dụng.

9.2. Plugin bảo mật WordPress (Wordfence...) có chặn được không?

Không đáng tin cậy. Request độc hại chạm tới lỗi trong lúc PHP parse request, trước khi code của plugin kịp chạy — kể cả firewall dạng prepend-file. Coi plugin là lớp bổ sung, không phải giải pháp.

9.3. Tôi dùng hosting shared, không có SSH thì sao?

Liên hệ nhà cung cấp hosting ngay và hỏi: "Server của tôi đã vá CVE-2026-109618 và CVE-2026-109619 chưa, bằng gói nào, ngày nào?" Nhà cung cấp uy tín đã vá trong tuần qua. Nếu họ trả lời vòng vo hoặc chưa vá, hãy cân nhắc chuyển host — dữ liệu của bạn đang nằm trên server đó.

9.4. Tắt session.upload_progress là đủ chưa?

Chưa. Nó chỉ giảm một đường dẫn của CVE-2026-109619. CVE-2026-109618 vẫn còn nguyên. Đây là biện pháp tạm thời trong lúc chờ vá, không phải bản vá.

9.5. PHP 7.4 của tôi chạy ổn định nhiều năm rồi, có nhất thiết nâng cấp không?

Với vụ này thì có. PHP 7.4 đã hết hỗ trợ, không có bản vá chính thức. Chạy hệ thống hết hỗ trợ, nối Internet, chứa dữ liệu thật — sau vụ PHP2Shell thì đó không còn là lựa chọn an toàn nữa. Hãy lên lịch nâng cấp lên nhánh 8.3 hoặc 8.4.

Nguồn tham khảo

Bình luận (0)

+ =
Zalo