php.net ยืนยันแล้วว่ามีช่องโหว่ critical สองตัว
วันที่ 20 ต.ค. ทีม security ของ PHP ประกาศล่วงหน้า ทั้งบนหน้าเว็บและใน mailing list php.announce ว่าจะออก security release สิ่งที่ประกาศยืนยันมีเท่านี้
- มีช่องโหว่ระดับ critical สองตัว ได้คะแนน CVSS v4.0 9.2 ทั้งคู่
- release ออกวันพุธที่ 21 ต.ค. 2569 เวลา 14:00 UTC ตรงกับ 21:00 น. เวลาไทย
- ทีมขอสิทธิ์ออกเร็วกว่านั้น ถ้ารายละเอียดของช่องโหว่ตัวใดตัวหนึ่งหลุดออกมา หรือเริ่มเห็นการโจมตีจริง
- เวอร์ชันที่ได้รับผลกระทบและเวอร์ชันที่แก้แล้วจะประกาศพร้อม release
ประกาศไม่ได้บอกเลข CVE ไม่ได้บอกว่าบั๊กอยู่ส่วนไหนของ PHP และไม่ได้ให้วิธีกันชั่วคราว บอกแค่ให้เตรียมตัวอัปเกรดทันทีที่ release ออก
ข่าวที่หลุดออกมาก่อนยังไม่มีใครยืนยัน
รายละเอียดหลุดออกมาตั้งแต่เช้าวันที่ 20 ต.ค. ก่อนกำหนดเปิดเผย ข่าวจึงมาจากหลายทาง และแต่ละที่ก็รู้ไม่เท่ากัน ตารางนี้แยกให้เห็นว่าใครพูดอะไรไว้
| ข่าว | ที่มา |
|---|---|
| เลข CVE คือ CVE-2026-109618 และ CVE-2026-109619 ตอนนี้ยังเป็นเลขที่จองไว้ ยังไม่มีคำอธิบาย | Sansec, Phoenix Security |
| watchTowr ยืนยันว่าช่องโหว่มีจริง และ reproduce ได้หนึ่งตัวคือ CVE-2026-109618 | Huntress |
| มี screenshot ของเครื่องมือโจมตีชื่อ PHP2Shell ที่อ้างว่าใช้ได้กับ PHP ทุกเวอร์ชันตั้งแต่ 5.4.0 | Sansec |
PoC ที่หลุดมาอ้างว่าเป็นบั๊ก heap use-after-free สองตัว ตัวหนึ่งอยู่ใน handler ของ session.upload_progress อีกตัวอยู่ในส่วนที่ parse multipart/form-data |
Phoenix Security |
| แพตช์จะออกให้แค่ 8.2 ถึง 8.5 ส่วน 8.1 ลงไปไม่มี | Phoenix Security, Help Net Security |
| เวอร์ชันที่แก้แล้วคือ 8.5.12, 8.4.27, 8.3.36 และ 8.2.35 | Phoenix Security ที่เดียว และติดป้ายไว้เองว่ายังต้องตรวจสอบ |
| Cloudflare เห็นการโจมตีเว็บ PHP ตั้งแต่ 07:43 UTC วันที่ 21 ต.ค. (14:43 น. เวลาไทย) และออกกฎ WAF แล้ว | Sansec |
| การโจมตีแบบหว่านน่าจะเริ่มภายใน 15 นาทีหลัง release | Sansec |
RCE (remote code execution) คือคนนอกสั่งรันโค้ดบนเซิร์ฟเวอร์ของเราได้จากระยะไกล ส่วน heap use-after-free คือโค้ดกลับไปใช้หน่วยความจำที่คืนไปแล้ว ซึ่งคนโจมตีมักต่อยอดจนรันโค้ดได้
เรื่องที่น่าจะเชื่อได้แน่ ๆ คือ 8.1 หมด security support ไปตั้งแต่ 31 ธ.ค. 2568 ตามตาราง supported versions ของ PHP เอง จึงไม่น่าได้แพตช์จาก PHP โดยตรง
อีกเรื่องที่ควรรู้ไว้ก่อนอ่านต่อคือ Sansec อ้างคำพูดของ Gina Peter Banyard หนึ่งใน core developer ของ PHP ว่า แพตช์คือวิธีกันเพียงทางเดียว วิธีกันชั่วคราวทุกอย่างในโพสต์นี้จึงเป็นแค่การซื้อเวลาจนกว่าจะแพตช์ได้ ส่วน PoC ที่ส่งต่อกันอยู่ Phoenix Security เตือนว่าอาจมีของอันตรายแฝงมาด้วย อย่าโหลดมารันเองครับ
middleware ของ Laravel ช่วยอะไรไม่ได้ถ้าบั๊กอยู่ตอนที่ PHP อ่าน request
ถ้า PoC ที่หลุดมาพูดถูก เรื่องนี้หนักกว่าช่องโหว่ใน framework ทั่วไป เพราะ PHP อ่าน body แบบ multipart/form-data และอัปเดต upload progress ลง session ตั้งแต่ก่อนเริ่มรัน public/index.php กว่า Laravel จะ boot ขึ้นมา PHP ก็แตกไฟล์ที่อัปโหลดลง $_FILES เสร็จแล้ว ตอนที่บั๊กเกิด middleware, validation, CSRF หรือ rate limit ของแอปจึงยังไม่ได้ทำงานเลย
แปลว่า request แบบ POST ที่ส่งเข้า PHP ได้ก็อาจยิงช่องโหว่ได้ทั้งหมด ไม่ต้องล็อกอิน และไม่ต้องมี route ที่รับอัปโหลด เว็บ Laravel, WordPress หรือ PHP ที่เขียนเองจึงอยู่ในข่ายเดียวกัน
เวอร์ชันที่ต้องอัปเดตไปให้ถึง
| branch | เวอร์ชันที่แก้แล้ว | หมายเหตุ |
|---|---|---|
| 8.5 | รอประกาศ (ข่าวว่า 8.5.12) | |
| 8.4 | รอประกาศ (ข่าวว่า 8.4.27) | |
| 8.3 | รอประกาศ (ข่าวว่า 8.3.36) | |
| 8.2 | รอประกาศ (ข่าวว่า 8.2.35) | |
| 8.1 ลงไป | ไม่น่ามีแพตช์จาก PHP | หมด security support แล้ว |
ถ้าเครื่องไหนยังเป็น 8.1 หรือเก่ากว่า ทางที่เหลือคืออัปเกรดขึ้น 8.2 ขึ้นไป รอ distro ที่ยังดูแล PHP ตัวนั้น backport แพตช์ให้ หรือเอาเครื่องออกจาก internet ไปไว้หลัง VPN ก่อน
ไล่ดูก่อนว่าแต่ละเครื่องรัน PHP อะไรอยู่จริง
ผมดูแลเซิร์ฟเวอร์ PHP อยู่ราวสิบกว่าเครื่อง มีทั้งของเราเองและของลูกค้า ส่วนใหญ่เป็น Ubuntu ที่ใช้ nginx กับ PHP-FPM พอเห็นประกาศ สิ่งแรกที่ทำคือไล่ดูว่าแต่ละเครื่องรัน PHP อะไรอยู่บ้าง เพราะเครื่องเดียวมักมี PHP มากกว่าหนึ่งเวอร์ชัน และตัวที่ php -v บอกก็อาจไม่ใช่ตัวที่เว็บใช้จริง
สิ่งที่อยากรู้จากแต่ละเครื่องมีไม่กี่อย่าง
- ลง PHP ไว้กี่ branch
- PHP-FPM ตัวไหนรันอยู่จริง รวมถึงตัวที่ control panel ลงไว้นอก
/etc/php - แต่ละเว็บใน nginx ส่ง request ไปที่ PHP เวอร์ชันไหน
- package ที่ลงไว้เป็นเวอร์ชันอะไร และลงมาจาก ondrej/php PPA หรือจาก Ubuntu เอง
ทุกข้อเป็นการอ่านอย่างเดียว ไม่ได้แก้อะไรบนเครื่อง วนดูผ่าน ssh ได้ครบทุกเครื่องในไม่กี่นาที พอเอาผลมาวางเทียบกัน ผมก็เจอหลายเรื่องที่ไม่คิดว่าจะเจอ
unattended-upgrades ไม่เคยอัปเดต PHP ที่ลงจาก PPA ให้เลย
เครื่องส่วนใหญ่ลง PHP จาก ondrej PPA เพราะได้เวอร์ชันใหม่กว่าที่ Ubuntu มีให้ แต่ unattended-upgrades ตั้งค่าเริ่มต้นให้อัปเดตเฉพาะ package ที่มาจาก Ubuntu เท่านั้น PHP จาก PPA จึงไม่เคยอัปเดตเองเลย บางเครื่องยังค้างอยู่ที่ 8.4.6 บางเครื่องอยู่ที่ 8.4.15 ทั้งที่ security update ของ Ubuntu ลงให้ครบทุกวัน
จะให้ PPA อัปเดตเองด้วยก็ทำได้ โดยเพิ่ม PPA เข้าไปในรายการ origin ที่ unattended-upgrades ยอมอัปเดต แต่ต้องยอมให้ PHP-FPM restart เองตอนไหนก็ได้ด้วย
PHP ตัวเดียวกันมาจากสามช่องทาง และแต่ละทางได้แพตช์ไม่พร้อมกัน
แพตช์เดียวกันจะมาถึงเครื่องของเราคนละเวลา แล้วแต่ว่าลง PHP มาจากไหน
- ondrej PPA ต้องรอ PPA build แพตช์ออกมาก่อน
- PHP ของ Ubuntu เอง Ubuntu ไม่ขยับเลขเวอร์ชันตาม upstream แต่ backport แพตช์เข้าเวอร์ชันเดิม แล้วประกาศผ่าน Ubuntu Security Notices บน Ubuntu 26.04 เลขจึงยังเป็น 8.5.4 แม้จะแพตช์แล้ว ต้องดูจาก USN แทนเลขเวอร์ชัน
- Homebrew บน macOS ต้องรอ formula อัปเดตก่อน
PHP ที่ลืมไปแล้วยังรันอยู่หลายตัว
ตัวที่ทำให้ตกใจที่สุดคือตัวที่ไม่มีใครใช้แล้วแต่ยังรันอยู่
- PHP 8.1 FPM ที่ control panel อย่าง DirectAdmin ลงไว้ ยังรันอยู่ทั้งที่ไม่มีเว็บไหนส่งมาแล้ว ตัวนี้หมด support และลงไว้นอก
/etc/phpถ้าดูแค่ในนั้นจะไม่เห็นเลย - PHP-FPM เวอร์ชันอื่นที่รันค้างไว้โดยไม่มีเว็บไหนใช้
- เซิร์ฟเวอร์เก่าที่เก็บไว้เผื่อ rollback แม้ DNS จะย้ายไปเครื่องใหม่แล้ว แต่เว็บเดิมยังตอบ request ที่ยิงเข้า IP ตรง ๆ อยู่ ส่วนเครื่องมือสแกนของคนโจมตีก็ไล่ยิงตาม IP อยู่แล้ว
- NAS บางรุ่นที่ระบบปฏิบัติการมี PHP ติดมาด้วย ตัวนี้เราแพตช์เองไม่ได้ ต้องรอผู้ผลิต หรือปิดไม่ให้เข้าจาก internet
ตัวที่ไม่มีใครใช้แล้ว หยุด service ไปเลยง่ายกว่าตามไปแพตช์ทีละตัว
Cloudflare กันให้ได้แค่เครื่องที่อยู่หลัง Cloudflare
ข่าวว่า Cloudflare ออกกฎ WAF สำหรับช่องโหว่นี้แล้ว แต่เซิร์ฟเวอร์ที่ผมดูแลมีทั้งที่อยู่หลัง Cloudflare และที่ไม่ได้อยู่ กฎนี้จึงกันได้แค่บางส่วน และเครื่องที่อยู่หลัง Cloudflare เองก็ยังโดนยิงตรงได้ ถ้า origin ยังรับ request จาก IP ไหนก็ได้ Sansec แนะนำให้ origin รับเฉพาะ IP ของ Cloudflare ไปด้วย
ปิด session.upload_progress ไว้ก่อนระหว่างรอแพตช์
session.upload_progress เป็นฟีเจอร์ของ PHP ที่เขียนความคืบหน้าของการอัปโหลดลง session ของ PHP เอง และเปิดไว้เป็นค่าเริ่มต้น แอป Laravel ไม่ได้ใช้ เพราะ Laravel มี session ของตัวเอง ส่วนแถบ progress ตอนอัปโหลดก็มาจาก JavaScript ฝั่ง browser ปิดไปจึงไม่กระทบแอป
ถ้าข่าวที่หลุดมาพูดถูก การปิดตัวนี้ปิดทางเข้าได้ทางเดียวจากสองทาง บั๊กใน multipart parser ยังอยู่ แต่ก็ช่วยลดความเสี่ยงได้บ้างระหว่างรอ ผมตั้ง session.upload_progress.enabled = 0 เป็นไฟล์แยกใน conf.d ของ PHP-FPM ทุกเวอร์ชัน จะได้ไม่ต้องแก้ php.ini หลัก และถอดออกได้ง่าย แล้วทดสอบ config ก่อน reload FPM และเช็คว่า FPM อ่านค่าใหม่จริง PHP ที่ control panel ลงไว้อ่าน php.ini คนละที่ ต้องตามไปตั้งใน config ของตัวนั้นด้วย หรือหยุดไปเลยถ้าไม่มีเว็บไหนใช้
Sansec แนะนำอีกทางคือบล็อก request แบบ multipart/form-data ที่ nginx ทางนี้ปิดได้ทั้งสองบั๊ก แต่จะทำให้อัปโหลดไฟล์ไม่ได้ทั้งเว็บ รวมถึงฟอร์มในหลังบ้านด้วย ผมจึงไม่ได้ทำ ใช้ได้เฉพาะเว็บที่ไม่มีการอัปโหลดเลยจริง ๆ
แพตช์ทันทีที่ release ออก แล้วเช็คว่าไม่มี process ไหนค้าง PHP ตัวเก่า
ก่อนแพตช์ให้ทำ snapshot ของเครื่องไว้ก่อน เพราะ ondrej PPA เก็บไว้แค่เวอร์ชันล่าสุด ถ้าแพตช์แล้วมีปัญหา จะสั่ง apt ให้ถอยกลับไปเวอร์ชันเดิมไม่ได้
พอ release ออก ผมอัปเดตเฉพาะ package ของ PHP ที่ลงไว้แล้ว ไม่อัปเกรดทั้งเครื่องไปพร้อมกัน จะได้มีเรื่องให้ไล่น้อยลงถ้ามีอะไรพัง แล้ว restart PHP-FPM ทุกเวอร์ชันที่รันอยู่
worker ที่รันค้างไว้ยังใช้ PHP ตัวเก่าที่อยู่ใน memory
apt เปลี่ยนไฟล์บนดิสก์ แต่ process ที่รันอยู่แล้วยังใช้ binary ตัวเดิมที่โหลดไว้ใน memory ต่อไป ตัวที่ต้องระวังคือ process ของ Laravel ที่รันยาว ๆ อย่าง Horizon, queue:work, Reverb และ Octane ต้องสั่งให้ worker พวกนี้จบตัวเอง (horizon:terminate, queue:restart, reverb:restart) แล้วให้ Supervisor หรือ systemd เปิดขึ้นมาใหม่ด้วย PHP ตัวใหม่ ถ้าไม่มีตัวคุมอยู่ worker จะหายไปเลย
ถ้าใช้ FrankenPHP แบบ static binary PHP จะฝังมาในตัว apt จึงไม่ได้แพตช์ให้ ต้องรอ FrankenPHP ออกเวอร์ชันที่ build กับ PHP ตัวที่แพตช์แล้ว
สุดท้ายผมไล่หา process ที่ยังค้าง binary เก่าอยู่ ไฟล์ที่ apt ลบไปแล้วแต่ยังมี process ใช้อยู่ Linux จะแสดงไว้ว่า (deleted) ถ้าไม่เหลือ process ไหนที่ยังใช้ PHP ตัวที่ลบไปแล้ว ก็แปลว่าทุกตัวใช้ PHP ตัวใหม่แล้ว
ตรวจหาร่องรอยหลังแพตช์
รายละเอียดหลุดมาตั้งแต่วันที่ 20 และ Cloudflare ก็เห็นการโจมตีก่อน release หลายชั่วโมง แพตช์เสร็จแล้วจึงควรดูต่อว่ามีใครเข้ามาก่อนหน้านั้นหรือเปล่า Huntress แนะนำให้ดูจากสามเรื่องนี้
- PHP-FPM ที่เปิดโปรแกรมอื่นขึ้นมา ปกติ worker ของ FPM ไม่ค่อยเปิดโปรแกรมอื่น นอกจากแอปจะเรียกเองอย่างตัวสร้าง PDF หรือแปลงวิดีโอ ถ้าเห็น FPM เปิด shell หรือโปรแกรมดาวน์โหลดอย่าง
curlกับwgetให้ดูต่อทันที - ไฟล์
.phpใหม่ในโฟลเดอร์เว็บ ที่ไม่ได้มากับการ deploy และไม่ได้อยู่ในvendorหรือไฟล์ cache ของ Laravel ถ้า deploy ด้วย git ไฟล์ที่ไม่ได้อยู่ใน repo จะเห็นได้ง่าย - crontab, user ใหม่ และ SSH key ที่เพิ่มเข้ามา หลังวันที่ 20 รวมถึง home ของ user ที่รันเว็บด้วย
ถ้าเจออะไรแปลก ๆ อย่าเพิ่งลบไฟล์ทิ้ง แยกเครื่องออกจาก network เก็บ log ไว้ก่อน แล้วค่อยไล่ดูว่าเข้ามาทางไหน





