CVE-2026-109618 và CVE-2026-109619 là hai lỗ hổng mới trong PHP, và assetnote/php2shell-scanner là tool CLI viết bằng Python để dò xem một host có dính hay không. Repo mới lên GitHub ngày 22/10/2026, tính đến lúc viết đã có 626 sao.
Nó làm gì, cụ thể
Scanner gửi một multipart control request tối thiểu, sau đó tối đa ba multipart probe. Mấy probe này dùng PHP array key lồng nhau sâu 62 tầng, kích thước tăng dần từ 1 MiB đến 20 MiB. Đây đúng là logic mà scanner nội bộ của Assetnote dùng.
Một target bị đánh dấu vulnerable khi rơi vào một trong các tín hiệu sau: probe gây ra lỗi PHP memory-exhaustion, một HTTP 500 rỗng khác biệt (differential empty HTTP 500), PHP-FPM worker chết, hoặc header version PHP lộ ra thuộc bản chưa patch. Còn mấy phản hồi 5xx ban đầu, các status từ chối request thông thường, hay HTTP 500 có nội dung nhưng không mang chữ ký fatal-error của PHP thì không bị coi là crash signal. Chi tiết này quan trọng, vì nếu gom hết 500 vào một rổ thì false positive sẽ đầy ra.
Mặc định tool test /index.php. Nếu URL bạn đưa vào có path thì path đó được giữ nguyên. Muốn test path khác thì dùng --path hoặc --path-file. Riêng target phpMyAdmin sẽ được retest tự động ở /show_config_errors.php. Redirect không được follow trừ khi bật --follow-redirects.
Có ba chế độ SAPI: auto (mặc định, áp cả rule của mod_php lẫn PHP-FPM, giống hành vi gộp của postmodule bên Assetnote), mod_php và fpm. Nếu bạn biết chắc target chạy SAPI nào thì giới hạn lại sẽ đỡ nhiễu hơn.
Về tác động mạng: mỗi path được test có thể nhận một control request 42 byte cộng ba probe, tổng cộng khoảng 29 MiB. Tool dừng probe ngay khi verdict đã chốt, và URL trùng nhau chỉ quét một lần. Vẫn là con số đáng để cân nhắc trước khi quăng vào production mà không báo trước.
Vì sao repo này đang được chú ý
Hai CVE mới, cộng thêm việc tool đến từ Assetnote Security Research Team, nhóm vốn nổi tiếng trong giới security research. Điểm khác biệt nằm ở chỗ đây không phải scanner viết vội: nó dùng lại logic đã build cho Searchlight Exposure Platform, tức là bản nội bộ đã chạy thật rồi mới tách ra thành tool public. Với người làm pentest hay sysadmin cần kiểm tra hàng loạt host PHP, một tool như vậy tiết kiệm kha khá thời gian so với tự viết PoC.
Con số 626 sao sau hai ngày với một tool chỉ có đúng một mục đích hẹp cho thấy nhu cầu thật. Không phải repo nào cũng được cộng đồng chú ý kiểu đó.
Cài và chạy thử
Yêu cầu Python 3.9 trở lên, cùng hai thư viện h11 và tqdm. Cài dependencies:
pip install -r requirements.txt
Hoặc dùng Docker, build image:
docker build -t php2shell-scanner .
Chạy với cùng bộ option như scanner.py:
docker run --rm php2shell-scanner -u https://example.com
Mount thư mục hiện tại để đọc host list và ghi kết quả:
docker run --rm -v "$PWD:/data" -w /data php2shell-scanner -l hosts.txt -o results.json
Quét một host:
python3 scanner.py -u https://example.com
Quét cả danh sách, chạy 20 thread và lưu JSON:
python3 scanner.py -l hosts.txt -t 20 -o results.json
Thêm header tùy chỉnh, hữu ích khi cần auth:
python3 scanner.py -u https://example.com -H "Authorization: Bearer token" -H "Cookie: session=abc"
Test path tùy chỉnh, hoặc chỉ dùng rule PHP-FPM:
python3 scanner.py -u https://example.com --path /phpinfo.php
python3 scanner.py -u https://example.com --path /index.php --path /admin.php
python3 scanner.py -u https://example.com --path-file paths.txt
python3 scanner.py -u https://example.com --sapi fpm
Một số option đáng để ý ngoài mấy cái trên: -t mặc định 10 thread, --timeout mặc định 60 giây, --all-results để ghi cả host không vulnerable, -v để xem lý do verdict kèm snippet response, -q để chỉ in host vulnerable, -k để bỏ qua verify TLS.
Ai nên dùng, dùng khi nào
Rõ ràng nhất là đội security hoặc pentester cần đánh giá nhanh một tập host PHP trước khi patch. Sysadmin quản lý nhiều web server cũng dùng được: quét một lượt, ai dính thì đưa lên lịch nâng cấp. Còn nếu bạn chỉ có một con server tự quản và biết chính xác version PHP đang chạy thì so version trực tiếp còn nhanh hơn.
Trường hợp hay gặp: một danh sách host từ bug bounty hoặc từ inventory nội bộ, cần biết cái nào rơi vào diện nghi vấn trước khi đào sâu. Cứ chạy với -l, xuất JSON, rồi lọc tiếp.
Hạn chế, và một cảnh báo khá quan trọng
README nói thẳng về false positive. Trên một số cấu hình PHP, khi multipart probe vượt memory_limit, bản đã patch và bản chưa patch trả về cùng một HTTP 500 rỗng, và scanner không phân biệt được. Nhóm phát triển đã reproduce trên PHP 8.4.27 đã patch với memory_limit từ 2M đến 32M, và trên PHP 8.3.36 ở mức 128M khi max_multipart_body_parts đặt từ 2785 trở lên. Ngưỡng chính xác có thể khác giữa các bản build.
Khi PHP không tiết lộ version, scanner không tách được kiểu OOM an toàn sau patch với hành vi trước patch. Nên kết quả phải đối chiếu lại với version PHP cài trên máy và các bản backport của vendor. Đừng tin verdict vulnerable 100% rồi đi hô hoán.
License MIT, thoải mái dùng và sửa. Repo mới hai ngày tuổi, tài liệu ở mức README, chưa có test suite công khai hay release tag. Đây là tool một mục đích, đừng kỳ vọng nó mở rộng thành framework quét lỗ hổng đa năng. Cái tên php2shell nghe khá giật gân, nhưng tool chỉ dò chứ không khai thác.
Tôi thấy điểm đáng giá nhất là việc tác giả ghi rõ giới hạn false positive thay vì im lặng. Một scanner tự nhận mình có thể sai trong điều kiện nào đó dễ tin hơn mấy tool hứa hẹn chính xác tuyệt đối. Nếu bạn đang có host PHP trong inventory, chạy thử với một path và bật -v để xem lý do verdict trước đã. Repo ở đây: assetnote/php2shell-scanner.
Câu hỏi thường gặp
php2shell-scanner có khai thác được lỗ hổng CVE-2026-109618 và CVE-2026-109619 không?
Không. Tool chỉ dò xem host có dính hay không, không khai thác. Cái tên php2shell nghe giật gân nhưng mục đích duy nhất là đưa ra verdict vulnerable hay không vulnerable dựa trên các tín hiệu như lỗi memory-exhaustion, HTTP 500 rỗng khác biệt, PHP-FPM worker chết hoặc header version PHP chưa patch.
Vì sao scanner báo vulnerable dù tôi đã patch PHP?
Đây là false positive đã được README nói rõ. Trên một số cấu hình, khi multipart probe vượt memory_limit, bản đã patch và chưa patch trả về cùng một HTTP 500 rỗng nên scanner không phân biệt được. Nhóm phát triển đã reproduce trên PHP 8.4.27 đã patch với memory_limit từ 2M đến 32M, và trên PHP 8.3.36 ở mức 128M khi max_multipart_body_parts đặt từ 2785 trở lên, nên cần đối chiếu lại với version PHP và bản backport của vendor.
Chạy scanner có ảnh hưởng nhiều đến mạng không?
Mỗi path được test có thể nhận một control request 42 byte cộng ba probe, tổng cộng khoảng 29 MiB. Tool dừng probe ngay khi verdict đã chốt và URL trùng nhau chỉ quét một lần, nhưng đây vẫn là con số đáng cân nhắc trước khi chạy vào production mà không báo trước.
