ควบคู่กับ CVE-2026-109618 ทาง PHP Group และฐานข้อมูลช่องโหว่ความปลอดภัยแห่งชาติสหรัฐฯ (NVD) ได้เปิดเผยช่องโหว่ความปลอดภัยระดับร้ายแรงสูงอีกหนึ่งตัวคือ CVE-2026-109619 ช่องโหว่นี้เกิดขึ้นที่เลเยอร์จัดการสถานะของกระบวนการประมวลผล (Process State Management) ภายใน Zend Engine ซึ่งทำให้เกิดการรั่วไหลของข้อมูลสถานะข้ามรอบการทำงาน (Cross-Request State Contamination) จนนำไปสู่การควบคุมทิศทางคำสั่งระบบ (Remote Code Execution – RCE)
ต้นตอของปัญหา (Root Cause Analysis)
โดยสถาปัตยกรรมปกติของ PHP-FPM (FastCGI Process Manager) ตัว Master Process จะ Fork ตัว Worker Processes ขึ้นมาเป็นจำนวนหนึ่งเพื่อคอยรับคำขอ HTTP และหมุนเวียนนำ Worker เดิมกลับมาใช้ซ้ำ (Process Reuse) เพื่อประสิทธิภาพสูงสุด
ในแต่ละรอบคำขอ (Request Cycle) PHP มีวงจรชีวิตชัดเจน
php_request_startup(): จัดเตรียม Global Variables, สภาพแวดล้อม และ Zend Memory Manager (ZMM)php_execute_script(): รันสคริปต์ PHPphp_request_shutdown(): คืนทรัพยากรหน่วยความจำของรอบนั้น และรีเซ็ตสถานะกลับสู่ค่าเริ่มต้น
ปัญหาของ CVE-2026-109619 เกิดจากความบกพร่องในขั้นตอน php_request_shutdown()
- Stale Global Pointer
ข้อมูลโครงสร้างระดับลึก (Internal Subsystem State) ในส่วนขยายหรือตัว Core Engine บางตัว เช่น การแคชโครงสร้าง Abstract Syntax Tree (AST), Hash Tables หรือสตรีมคอนเท็กซ์ มีการคืนหน่วยความจำ (Free) ตัวอ็อบเจกต์ไปแล้ว แต่ ไม่ได้เซ็ต Pointer ที่อยู่ในหน่วยความจำระดับ Global/Process ให้เป็นNULL - Dangling Global Reference
เมื่อ Worker นั้นจบการทำงานของ Request แรก Global Struct ยังคงถือ Dangling Pointer ที่ชี้ไปยังตำแหน่งหน่วยความจำเดิมใน Heap ที่ถูกปล่อยว่างไปแล้ว - Cross-Request Confusion
เมื่อมีคำขอใหม่ (Request ที่สอง) วิ่งเข้ามาหา Worker ตัวเดิม ตัวประมวลผลเข้าใจผิดว่าโครงสร้างระบบนั้นถูกเตรียมไว้แล้ว จึงนำ Dangling Pointer เก่าไปใช้งานต่อทันทีโดยไม่ผ่านการจัดสรรใหม่
ลำดับการโจมตี (Exploitation Flow)
ผู้โจมตีอาศัยลักษณะการทำงานวนซ้ำของ Worker Process ในการสร้างสภาวะ Use-After-Free ข้าม Request
[Request 1: Priming Request]
ผู้โจมตีส่ง Payload บีบให้เกิด Partial Failure ในจังหวะ Shutdown
│
▼
ทรัพยากรบางส่วนถูก Free แต่ Global Pointer ยังค้างอยู่ (Stale State)
[Request 2: Grooming & Hijacking Request]
ผู้โจมตีส่ง Request ถัดไปเข้ามายัง Worker Process ตัวเดิม
│
├─ จัดวาง Memory (Heap Spraying) ให้ทับตำแหน่งที่เพิ่งถูก Free ไป
│
▼
PHP นำ Global Pointer เดิมมาเรียกใช้งาน ฟังก์ชันพอยน์เตอร์ถูกชี้ไปยัง Shellcode
│
▼
Remote Code Execution (RCE) สำเร็จ
เนื่องจากช่องโหว่นี้ผูกติดกับวงจรชีวิตของโปรเซส Worker ทำให้ระบบที่ใช้ PHP-FPM แบบดั้งเดิมโดยไม่มีการรีไซเคิล Worker มีความเสี่ยงต่อการถูกทำ Exploit สูงมาก
เวอร์ชันที่ได้รับผลกระทบ
- PHP 8.2.x
ต่ำกว่ารุ่น 8.2.35 - PHP 8.3.x
ต่ำกว่ารุ่น 8.3.36 - PHP 8.4.x
ต่ำกว่ารุ่น 8.4.27 - PHP 8.5.x
ต่ำกว่ารุ่น 8.5.12
แนวทางแก้ไขและลดผลกระทบ
อัปเกรดแพ็กเกจทันที
อัปเกรด PHP Core และโมดูลทั้งหมดเป็นเวอร์ชัน 8.5.12 (หรือเวอร์ชันแพตช์ล่าสุดของสาย 8.2, 8.3, 8.4) ซึ่งคอมไพล์โค้ดที่ทำ Explicit Nullification ให้กับ Global Contexts ในขั้นตอน php_request_shutdown()
Bash
sudo apt update && sudo apt --only-upgrade install "php8.5*"
sudo systemctl restart php8.5-fpm
มาตรการบรรเทาความเสียหายในระดับคอนฟิก (Mitigation)
หากยังไม่สามารถอัปเกรดไบนารีได้ทันที ให้ตั้งค่าตัดวงจรชีวิตของ Worker ไม่ให้มีอายุยาวพอที่จะถูกทำ Cross-Request Exploitation:
ใน /etc/php/8.5/fpm/pool.d/www.conf
Ini, TOML
; สั่งทำลาย Worker และสร้างใหม่บ่อยขึ้น
pm.max_requests = 100
; กำหนด Process Management ให้ยืดหยุ่นเพื่อลดอายุค้างของ Worker
pm = dynamic
บันทึกไฟล์แล้วสั่ง reload:
Bash
sudo systemctl reload php8.5-fpm
การลดค่า pm.max_requests จะบังคับให้ OS เคลียร์ Address Space ทั้งหมดของ Worker Process นั้นทิ้งอย่างสมบูรณ์หลังทำงานครบจำนวนครั้งที่กำหนด ช่วยลดหน้าต่างเวลาที่ผู้โจมตีจะส่ง Request ที่สองเข้ามาทับตำแหน่ง Memory เดิมได้