เมื่อวันที่ 21 ตุลาคม 2026 โครงการ PHP ได้ออกรีลีสฉุกเฉินสำหรับบั๊กวิกฤตสองตัวที่อนุญาตให้ผู้โจมตีที่ไม่ผ่านการยืนยันตัวตนรันโค้ดบนเว็บเซิร์ฟเวอร์ได้ ทั้งคู่ถูกติดตามเป็น CVE-2026-109618 และ CVE-2026-109619 และมีชื่อว่า PHP2Shell ทั้งสองได้คะแนน 9.2 บน CVSS v4.0 ทั้งคู่กระทบทุกการตั้งค่า PHP ที่ให้บริการ HTTP และ honeypot ของ Amazon บันทึกความพยายามใช้ช่องโหว่เมื่อวันที่ 17 ตุลาคม สี่วันก่อนที่แพตช์จะมีอยู่
PHP ทำงานบน 69.3% ของเว็บไซต์ที่ทราบภาษาเซิร์ฟเวอร์ไซด์ (W3Techs) หากคุณรัน PHP API, แบ็กเอนด์ Laravel หรือ Symfony, เว็บไซต์ WordPress หรืออิมเมจคอนเทนเนอร์ที่มี PHP ฝังอยู่ แสดงว่าคุณได้รับผลกระทบนี้
คู่มือนี้ครอบคลุมว่าบั๊กทำอะไรได้บ้าง เวอร์ชันใดได้รับผลกระทบ วิธีตรวจสอบเซิร์ฟเวอร์ของคุณ การบรรเทาผลกระทบช่วยได้จริงแค่ไหน และวิธีพิสูจน์ว่า API ของคุณยังทำงานได้หลังแพตช์
สรุปสั้น ๆ
| คำถาม | คำตอบ |
|---|---|
| มันคืออะไร? | บั๊กความปลอดภัยของหน่วยความจำสองตัวในระบบจัดการคำขอของ PHP ที่ถูกล่ามโซ่ให้กลายเป็นการรันโค้ดจากระยะไกล |
| CVEs | CVE-2026-109618 (ความเสียหายจากหน่วยความจำหมด), CVE-2026-109619 (สถานะค้างเก่า, use-after-free) |
| ความรุนแรง | CVSS v4.0 9.2 ต่อตัว (ID ที่รั่วไหลในช่วงแรกบอกว่า 10.0; PHP กล่าวว่าไม่ถูกต้อง) |
| ต้องยืนยันตัวตนหรือไม่? | ไม่ |
| ได้รับผลกระทบ | ทุก SAPI ที่ให้บริการ HTTP: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed |
| เวอร์ชันที่แก้ไขแล้ว | 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| PHP 8.1 และเก่ากว่า | ไม่มีรีลีสอย่างเป็นทางการ; มี backport ซอร์สโค้ดขั้นต่ำสำหรับ 7.4, 8.0, 8.1; 5.4 ถึง 7.3 ไม่ได้รับการแก้ไขใด ๆ |
| ถูกใช้ช่องโหว่แล้วหรือ? | พบความพยายามตั้งแต่ 17 ตุลาคม (Amazon), Cloudflare รายงานการโจมตีระยะแรก |
| การแก้ไข | อัปเกรด, รีสตาร์ท worker ทุกตัว วิธีเลี่ยงช่วยลดความเสี่ยงแต่ไม่ได้ปิดช่องโหว่ |
PHP2Shell คืออะไรกันแน่
บั๊กทั้งสองมีสาเหตุรากเดียวกัน: PHP อาจทิ้งหน่วยความจำไว้ในสภาพที่เสียหายเมื่อคำขอสิ้นสุดลงอย่างผิดปกติ และโค้ดทำความสะอาดก็เชื่อถือสภาพที่เสียหายนั้น
CVE-2026-109618: ความเสียหายจากหน่วยความจำหมดระหว่างการเริ่มต้นคำขอ เมื่อ PHP แยกวิเคราะห์ข้อมูลฟอร์มลงใน $_POST โค้ดตารางแฮชของ Zend engine จะเพิ่มตัวนับรายการก่อนที่จะจัดสรรคีย์ใหม่ การวิเคราะห์ของ Datadog สืบย้อนไปถึง _zend_hash_str_add_or_update_i() ใน zend_hash.c หากการจัดสรรนั้นเกิน memory_limit PHP จะเกิด fatal error และยกเลิกการแทรก ตัวนับตอนนี้รวมบัคเก็ตที่ไม่เคยถูกตั้งค่าไว้ด้วย เมื่อปิดระบบ PHP จะทำลาย $_POST และถือว่าทุกบัคเก็ตที่นับไว้มีอยู่จริง
ส่วนที่น่าทำให้ทีม API กังวล: สิ่งนี้เกิดขึ้นขณะที่ PHP ยังคงแยกวิเคราะห์เนื้อหาคำขอ ก่อนที่โค้ดของคุณจะทำงานแม้แต่บรรทัดเดียว middleware การยืนยันตัวตน ตัวจำกัดอัตรา และการตรวจสอบอินพุตของคุณจะไม่เห็นคำขอนั้น Datadog ทำให้เกิดซ้ำได้ด้วยเนื้อหา application/x-www-form-urlencoded ธรรมดา ไม่ใช่การอัปโหลดไฟล์
CVE-2026-109619: สถานะโกลบอลค้างเก่าข้ามคำขอ PHP เก็บสถานะระดับ worker บางอย่างที่ชี้ไปยังหน่วยความจำต่อคำขอ หาก fatal error ขัดจังหวะการรีเซ็ตสถานะนั้น หรือการวินิจฉัยตอนปิดระบบที่มาช้าสร้างสถานะนั้นขึ้นใหม่หลังทำความสะอาด คำขอถัดไปบน worker เดียวกันจะอ่านหน่วยความจำที่ถูกคืนแล้ว PHP ยืนยันสองเส้นทาง:
- แบ็กเทรซจาก fatal error (PHP 8.5 เท่านั้น): การวินิจฉัยการกำหนดค่าในคำขอถัดมาอ่านสถานะแบ็กเทรซที่ตกค้าง ยืนยันการรันคำสั่งบน mod_php
- การประมวลผลอัปโหลด: หลัง fatal error ความคืบหน้าการอัปโหลดเซสชันอาจทิ้งสถานะไว้สำหรับการอัปโหลดครั้งถัดไป ความคืบหน้าการอัปโหลดเปิดอยู่โดยค่าเริ่มต้นและทำงานแม้แอปของคุณไม่เคยเรียก
session_start()ยืนยันการรันคำสั่งบน mod_php และ PHP-FPM
ทีมความปลอดภัยของ PHP จัดให้ mod_php เป็นความเสี่ยงสูงสุด เนื่องจากการโจมตีที่สาธิตนั้นทำงานจากคำขอเดียวที่ไม่ผ่านการยืนยันตัวตนก่อนที่โค้ดแอปพลิเคชันใด ๆ จะโหลด
ใครเป็นผู้ค้นพบ (และทำไม AI ถึงอยู่ในพาดหัวข่าว)
บั๊กเหล่านี้ย้อนไปถึงโค้ดที่เริ่มมีใน PHP 5.4.0 ดังนั้นมันอยู่ในโค้ดเบสมากกว่าทศวรรษ มูลนิธิ PHP ให้เครดิต Calif, OpenAI และ Wiz
รายงานจาก Decrypt และ The Next Web กล่าวว่านักวิจัย Calif อย่าง Ryan Austin ค้นพบข้อบกพร่องในเดือนสิงหาคมระหว่างการตรวจสอบซอร์สโค้ดที่ได้รับความช่วยเหลือจาก GPT-5.6 Sol ของ OpenAI OpenAI กล่าวว่าทีมของตนค้นพบเวอร์ชันที่สมบูรณ์กว่าในเดือนกันยายนโดยเป็นส่วนหนึ่งของงาน “Patch the Planet” ของบริษัท Wiz กล่าวว่าตนค้นพบบั๊กทั้งสองด้วยตัวเองโดยใช้ Gemini 4 Argon, Wiz Atlas และ GPT-5.6 Sol เครดิตยังเป็นที่โต้แย้ง แต่สิ่งที่ควรตระหนักนั้นชัดเจน การตรวจสอบซอร์สโค้ดที่ช่วยโดย AI กำลังค้นพบบั๊กหน่วยความจำที่มีอายุหลายทศวรรษในโครงสร้างพื้นฐานหลัก และผู้โจมตีก็มีโมเดลเดียวกัน
ไทม์ไลน์: ทำไมแพตช์จึงออกก่อนหนึ่งวัน
| วันที่ (2026) | เกิดอะไรขึ้น |
|---|---|
| สิงหาคมถึงกันยายน | Calif, OpenAI และ Wiz รายงานบั๊กแบบส่วนตัว |
| 17 ต.ค. | honeypot MadPot ของ Amazon บันทึกความพยายามใช้ช่องโหว่ |
| 20 ต.ค. | ID CVE รั่วไหลบน Hacker News และโซเชียลมีเดีย; PHP โพสต์ประกาศล่วงหน้า; CERT-EU ออกคำแนะนำ 2026-018 |
| 21 ต.ค. 14:00 UTC | PHP ออกแพตช์ เลื่อนจาก 22 ต.ค. หลังการรั่วไหล; CISA เผยแพร่การแจ้งเตือน; Cloudflare รายงานการโจมตีระยะแรก |
| 22 ต.ค. | ยังไม่มี CVE ใดอยู่ในแคตตาล็อก KEV ของ CISA |
Amazon แนะนำให้ตรวจสอบย้อนตั้งแต่วันที่ 17 ตุลาคม (FAQ ของ Tenable ติดตามไทม์ไลน์ทั้งหมด) ไม่ใช่วันที่เปิดเผย ณ เวลาที่ออกรีลีส ทีม PHP กล่าวว่าตนตรวจสอบโค้ด proof-of-concept ที่ปรากฏหลังการรั่วไหลและไม่พบ exploit ที่ใช้งานได้ watchTowr กล่าวภายหลังว่าตนทำให้บั๊กทั้งสองเกิดซ้ำได้ ให้ถือว่า repo “PoC” ใด ๆ ที่คุณพบนั้นน่าสงสัย: โค้ด exploit ที่ยังไม่ผ่านการตรวจสอบมักมาพร้อมมัลแวร์
คุณได้รับผลกระทบหรือไม่? ตรวจสอบได้ในห้านาที
1. ตรวจสอบรันไทม์ที่ให้บริการทราฟฟิก ไม่ใช่แล็ปท็อปของคุณ ไบนารี CLI อาจแตกต่างจากโมดูล FPM หรือ Apache ในเรื่องเวอร์ชันและการกำหนดค่า
# On the server or inside the running container
php -v
php-fpm -v
# Apache mod_php: check the loaded module version
apachectl -M 2>/dev/null | grep -i php
หรือเปิดเผยครั้งเดียวจากเส้นทางที่ได้รับการป้องกันแล้วลบออกภายหลัง:
<?php echo PHP_VERSION, ' ', PHP_SAPI;
2. เปรียบเทียบกับเวอร์ชันที่แก้ไขแล้ว
| สาย | มีช่องโหว่ | แก้ไขใน |
|---|---|---|
| 8.5 | < 8.5.12 | 8.5.12 |
| 8.4 | < 8.4.27 | 8.4.27 |
| 8.3 | < 8.3.36 | 8.3.36 |
| 8.2 | < 8.2.35 | 8.2.35 |
| 7.4 ถึง 8.1 | ทั้งหมด | เฉพาะ backport ซอร์สโค้ด หรือ LTS ของผู้ขาย |
| 5.4 ถึง 7.3 | ทั้งหมด | ไม่มีการแก้ไข |
Debian, Ubuntu, Red Hat และดิสโทรอื่น ๆ มัก backport การแก้ไขโดยไม่เปลี่ยนสตริงเวอร์ชันต้นทาง หาก php -v แสดงเลขที่เก่ากว่า ให้อ่านคำแนะนำของดิสโทรของคุณก่อนตื่นตระหนก
3. ทำบัญชี PHP ที่ซ่อนอยู่ คอนเทนเนอร์ที่สร้างจาก FROM php:8.3-fpm หลายเดือนก่อน อุปกรณ์จากผู้ขาย บิลด์ที่คอมไพล์เอง แผงผู้ดูแลบนซับโดเมนที่ถูกลืม Cisco ได้เปิดคำแนะนำให้ตรวจสอบสายผลิตภัณฑ์ของตนแล้ว Shodan นับโฮสต์ PHP ที่หันสู่อินเทอร์เน็ตได้มากกว่า 1.9 ล้านโฮสต์; นักวิจัยคนหนึ่งประเมินว่าอาจมี 1.3 ล้านหรือมากกว่าที่มีช่องโหว่
วิธีแพตช์
# Debian / Ubuntu (Ondřej Surý PPA or distro packages)
sudo apt update && sudo apt install --only-upgrade 'php8.*'
# RHEL / Rocky / Alma with Remi
sudo dnf upgrade 'php*'
# Official Docker image: rebuild on a fixed tag
docker pull php:8.4.27-fpm
docker build --pull -t my-api:patched .
จากนั้นทำขั้นตอนที่ทีมส่วนใหญ่มองข้าม: รีสตาร์ทหรือแทนที่ PHP worker ทุกตัว พูล FPM ที่กำลังทำงานยังเก็บไบนารีเก่าไว้ในหน่วยความจำ รีสตาร์ท php-fpm รีโหลด Apache และโรลคอนเทนเนอร์ทุกตัว CVE-2026-109619 เกี่ยวกับสถานะที่คงอยู่ข้ามคำขอภายใน worker ดังนั้น worker ที่ยังไม่รีสตาร์ทยังคงมีช่องโหว่
บน 8.1 หรือเก่ากว่า คุณมีสามตัวเลือก: แพ็กเกจ LTS จากผู้ขาย การบิลด์จาก backport ซอร์สโค้ดของ PHP หรือการอัปเกรดเป็น 8.2+ CISA แนะนำให้นำระบบ PHP ที่แพตช์ไม่ได้ออฟไลน์ และ UK NCSC กับ FBI กล่าวเช่นเดียวกัน
การบรรเทาผลกระทบหากคุณยังแพตช์วันนี้ไม่ได้
สิ่งเหล่านี้ช่วยซื้อเวลา Gina Peter Banyard จากทีมหลัก PHP บอกกับ BleepingComputer ว่าไม่มีมาตรการบรรเทาใดที่บล็อกการโจมตีได้อย่างสมบูรณ์
สำหรับ CVE-2026-109618:
- ตั้ง
memory_limit=-1ในจุดที่แอปไม่สามารถโอเวอร์ไรด์ได้ (php_admin_valueในพูล FPM หรือการกำหนดค่า Apache) สิ่งนี้บล็อกเส้นทางที่ทราบ แต่ไม่ใช่ทุกวิธีที่การจัดสรรหน่วยความจำจะล้มเหลว - ลด
post_max_size(8M เมื่อไม่มีการอัปโหลด, 32M เมื่อมีการอัปโหลด) - จำกัดขนาดเนื้อหาคำขอที่ reverse proxy (
client_max_body_sizeใน nginx) และตั้งขีดจำกัดหน่วยความจำของคอนเทนเนอร์หรือ cgroup เป็นขอบเขตความพร้อมใช้งาน - อย่าใช้ขีดจำกัดโปรเซส
RLIMIT_ASหรือRLIMIT_DATAเพราะอาจทำให้เกิดความล้มเหลวในการจัดสรรหน่วยความจำแบบที่ exploit ต้องการได้
สำหรับ CVE-2026-109619:
- ตั้ง
session.upload_progress.enabled=0ในการกำหนดค่าที่โหลดก่อนการแยกวิเคราะห์คำขอ - บน PHP 8.5 ให้ตั้ง
fatal_error_backtraces=0ด้วย - การซ่อนข้อผิดพลาดด้วย
display_errors=0หรือ@ไม่ช่วยอะไร สถานะค้างเก่ายังคงอยู่
ที่ขอบเครือข่าย: Cloudflare ปรับใช้กฎ WAF สำหรับเวกเตอร์ที่ทราบในทุกแพ็กเกจ รวมถึงฟรี CTO ของบริษัทเรียกกฎเหล่านี้ว่าชั่วคราว
หลังเปลี่ยน php.ini ใด ๆ ให้รีสตาร์ท worker ทุกตัว ไม่อย่างนั้นจะไม่มีผล
สัญญาณว่าคุณถูกโจมตีไปแล้ว
คำแนะนำการตรวจจับของ Datadog สรุปได้เป็นสี่สัญญาณ:
- บรรทัดในล็อก:
PHP Fatal error: Allowed memory size of ... bytes exhaustedพร้อมUnknown on line 0ซึ่งหมายความว่า PHP ตายระหว่างการเริ่มต้นคำขอ ก่อนสคริปต์ใด ๆ จะทำงาน - Apache crash:
AH00052: child pid ... exit signal Segmentation fault (11)ซึ่งอาจเป็นการเดา exploit ที่ล้มเหลว - การโพสต์ฟอร์มผิดปกติ: ชื่อฟิลด์ยาวหลายเมกะไบต์ หรือไบต์ไบนารีและ null ไบต์ในฟิลด์ที่ชื่อว่าง
- สัญญาณที่ชัดเจนที่สุด: worker เว็บ (
php-fpm,apache2,httpd) สร้างเชลล์ขึ้นมา
อย่าเชื่อรหัสสถานะ exploit ที่ปรับปรุงแล้วของ Datadog ส่งคืน HTTP 200 และ worker ยังคงทำงาน ค้นล็อกย้อนไปถึงวันที่ 17 ตุลาคม
พิสูจน์ว่า API ของคุณยังทำงานหลังแพตช์: ให้เอเจนต์ของคุณรันมัน
การแพตช์ PHP ในโปรดักชันภายใต้แรงกดดันคือวิธีที่คุณจะรู้ว่าการอัปเวอร์ชันไมเนอร์เปลี่ยนแปลงอะไรไป ก่อนและหลังคุณโรลการแก้ไข ให้รันชุดทดสอบ API ของคุณกับ staging และให้ coding agent ของคุณทำผ่าน Apidog CLI
ตั้งค่า (ครั้งเดียว):
npm install -g apidog-cli
apidog auth login --with-token <your-access-token>
apidog test-suite list --project <projectId>
พรอมป์ต์เดียวถึง Claude Code, Codex หรือ Cursor:
เราเพิ่งอัปเกรด PHP เป็น 8.4.27 บน staging สำหรับ PHP2Shell ใช้ Apidog CLI รันชุดทดสอบ regression ของเรากับสภาพแวดล้อม staging เขียนรายงาน HTML และ JUnit และสรุป endpoint ที่ล้มเหลว จากนั้นยืนยันว่า POST ที่มีเนื้อหาเกิน client_max_body_size ของ nginx ถูกปฏิเสธด้วย 413 ที่พร็อกซีแทนที่จะไปถึง PHPสิ่งที่เอเจนต์รัน:
apidog test-suite run <testSuiteId> --project <projectId> -e <stagingEnvId>
apidog run --test-suite <testSuiteId> --project <projectId> -e <stagingEnvId> \
-r cli,html,junit --out-dir ./php2shell-reports --upload-report
-r เลือกตัวรายงาน, --out-dir กำหนดตำแหน่งที่รายงานจะไปอยู่ และ --upload-report ผลักสรุปที่คุณเปิดในแอป Apidog ได้ เพิ่ม --notification-failed-event <targetId> เพื่อแจ้งทีมของคุณเฉพาะเมื่อมีบางอย่างพัง ใส่บรรทัด apidog run เดียวกันลงใน CI เพื่อให้ทุกอิมเมจ PHP ที่สร้างใหม่ถูกทดสอบก่อนส่งออก คู่มือการตั้งค่า Claude Code และ คำแนะนำไปป์ไลน์ CI/CD ครอบคลุมทั้งสองอย่างโดยละเอียด
รันชุดทดสอบหนึ่งครั้งบนเวอร์ชันเก่าเพื่อสร้าง baseline หนึ่งครั้งหลังอัปเกรด แล้ว diff หากการทดสอบที่คุณไม่เคยคาดว่าจะล้มเหลวกลับล้มเหลว คุณจะรู้ก่อนผู้ใช้ของคุณ ดาวน์โหลด Apidog เพื่อสร้างและจัดการชุดทดสอบที่ CLI รัน
คำถามที่พบบ่อย
PHP2Shell ถูกใช้ช่องโหว่หรือยัง? Amazon พบความพยายามตั้งแต่ 17 ตุลาคม และกล่าวว่าตอนนี้มีการใช้ช่องโหว่อย่างแพร่หลาย; Cloudflare และ watchTowr ก็รายงานการโจมตีเช่นกัน CISA ยังไม่ยืนยันการใช้งานช่องโหว่ ณ วันที่ 22 ตุลาคม
เฟรมเวิร์กของฉันปกป้องฉันได้ไหม? ไม่ CVE-2026-109618 ทำงานขณะ PHP แยกวิเคราะห์เนื้อหา ก่อน Laravel, Symfony หรือ WordPress จะโหลด
ฉันใช้ shared hosting ควรทำอย่างไร? ตรวจสอบหน้าสถานะของโฮสต์คุณ SiteGround และรายอื่นกล่าวว่าได้แพตช์แล้ว หากโฮสต์ของคุณยังไม่ประกาศอะไร ให้ถาม
session.upload_progress.enabled=0 เพียงพอหรือไม่? ไม่ มันครอบคลุมเพียงเส้นทางหนึ่งของ CVE หนึ่งตัว ต้องแพตช์
ฉันต้องหมุนเวียนความลับหรือไม่? CVE-2026-109619 อนุญาตให้เปิดเผยหน่วยความจำ หากล็อกแสดงสัญญาณการถูกบุกรุกตั้งแต่ 17 ตุลาคม ให้หมุนเวียนรหัสผ่านฐานข้อมูล คีย์ API และความลับเซสชันที่โปรเซส PHP สามารถอ่านได้
สรุปสุดท้าย
อัปเกรดเป็น 8.5.12, 8.4.27, 8.3.36 หรือ 8.2.35 รีสตาร์ท worker ทุกตัว ค้นหา PHP ที่คุณลืมไป ตรวจสอบล็อกย้อนไปถึงวันที่ 17 ตุลาคม จากนั้นรันการทดสอบ API ของคุณเพื่อให้การแก้ไขไม่กลายเป็นการดาวน์ไทม์ครั้งถัดไป หาก PHP ของคุณอยู่บน 8.1 หรือเก่ากว่า นี่คือสัปดาห์ที่จะย้ายออกไปได้เสียที
