สรุปสั้น

ข้อมูลเพียง 11 ไบต์สามารถทำให้เซิร์ฟเวอร์ OpenSSL ที่ยังไม่ได้แพตช์กันหน่วยความจำไว้สูงถึง 131 กิโลไบต์ เพื่อรอข้อความที่ไม่มีวันเดินทางมาถึง และบนระบบที่ใช้ไลบรารี glibc ซึ่งทีม Red Team ของบริษัท Okta ทดสอบ หน่วยความจำก้อนนั้นจะหายไปจนกว่าจะรีสตาร์ตโปรเซส ช่องโหว่ปฏิเสธการให้บริการ (denial-of-service หรือ DoS) นี้ถูกตั้งชื่อว่า HollowByte โดยทีมที่ค้นพบและรายงาน ซึ่งเผยแพร่รายละเอียดเมื่อวันพฤหัสบดีที่ผ่านมา ประเด็นที่ทำให้เรื่องนี้น่ากังวลเป็นพิเศษคือโครงการ OpenSSL ได้ปล่อยแพตช์แก้ไขไปตั้งแต่เดือนมิถุนายนโดยไม่ออกหมายเลข CVE ไม่มีประกาศเตือน และไม่มีบันทึกใน changelog ที่ชี้ไปยังการแก้ไขนี้เลย

รุ่นที่ได้รับการแก้ไขแล้วคือ OpenSSL 4.0.1, 3.6.3, 3.5.7, 3.4.6 และ 3.0.21 ซึ่งทั้งหมดออกวันที่ 9 มิถุนายน 2569 ส่วนทุกรุ่นก่อนหน้านั้นในสายเดียวกันล้วนมีช่องโหว่ ปัญหาคือกระบวนการแพตช์ตามปกติขององค์กรจะไม่มีทางชี้ให้เห็นว่าต้องอัปเดต เพราะไม่มีตัวระบุให้เครื่องมือสแกนจับคู่ และไม่มีประกาศเตือนให้อ่าน ในการทดสอบกับ NGINX ของบริษัท Okta เซิร์ฟเวอร์ขนาด 1 GB ถูกระบบฆ่าโปรเซสเพราะหน่วยความจำหมด (OOM-killed) โดยมีหน่วยความจำ 547 MB ค้างอยู่ในเศษที่แตกกระจาย ส่วนเซิร์ฟเวอร์ขนาด 16 GB ถูกล็อกหน่วยความจำระบบไปถึง 25% โดยที่จำนวนการเชื่อมต่อไม่เคยเกินเพดานที่ตั้งไว้เลย ซึ่งเป็นเหตุผลที่ทีม Red Team ระบุว่า “มาตรการจำกัดจำนวนการเชื่อมต่อแบบมาตรฐานจะหยุดมันไม่ได้”

รายละเอียดข่าว

เว็บไซต์ The Hacker News รายงานเมื่อวันที่ 18 กรกฎาคม 2569 ว่าทีม Red Team ของบริษัท Okta เป็นผู้รายงานและตั้งชื่อช่องโหว่นี้ พร้อมเผยแพร่รายละเอียดทางเทคนิคต่อสาธารณะ โดยไม่ได้ปล่อยโค้ดโจมตีออกมาพร้อมกัน และ ณ วันที่ 18 กรกฎาคม 2569 ยังไม่พบคลังโค้ดพิสูจน์แนวคิด (proof-of-concept) เผยแพร่บน GitHub

รากของปัญหาคือ OpenSSL เชื่อคำบอกเล่าของผู้โจมตีโดยไม่ตรวจสอบ ทุกข้อความในกระบวนการจับมือ (handshake) ของ TLS จะมีส่วนหัวขนาด 4 ไบต์ ซึ่งใน 3 ไบต์ของส่วนหัวนั้นเป็นตัวประกาศว่าเนื้อหาที่จะตามมามีความยาวเท่าใด OpenSSL รุ่นเก่าจะขยายบัฟเฟอร์รับข้อมูลให้เท่ากับขนาดที่ประกาศไว้ทันทีที่ส่วนหัวมาถึง คือก่อนที่เนื้อหาแม้แต่ไบต์เดียวจะปรากฏ และก่อนที่การตรวจสอบของกระบวนการจับมือเองจะทำงาน สำหรับข้อความ ClientHello ที่เข้ามาจากภายนอก เพดานการจองอยู่ที่ 131 KB จากนั้นเธรดที่ทำงานอยู่ก็จะค้างรอเนื้อหาที่ไม่มีวันมาถึง ทั้งหมดนี้เกิดขึ้นโดยไม่ต้องยืนยันตัวตน ไม่ต้องมีเซสชัน และไม่ต้องแลกเปลี่ยนกุญแจใดๆ

หากพิจารณาแค่นี้ก็เป็นเพียงการโจมตีแบบทำให้การเชื่อมต่อหมด ซึ่งเป็นเทคนิคเก่าแก่พอๆ กับ Slowloris แต่สิ่งที่ทำให้ HollowByte ทิ้งร่องรอยไว้อย่างถาวรคือพฤติกรรมของ glibc เมื่อผู้โจมตีตัดการเชื่อมต่อ OpenSSL จะคืนบัฟเฟอร์นั้น แต่ glibc กลับเก็บก้อนหน่วยความจำขนาดเล็กและขนาดกลางไว้ใช้ซ้ำแทนที่จะคืนให้เคอร์เนล การโจมตีนี้จะสุ่มเปลี่ยนขนาดที่ประกาศไว้ในทุกการเชื่อมต่อ ซึ่งในการทดสอบของบริษัท Okta เพียงพอที่จะทำให้ตัวจัดสรรหน่วยความจำไม่สามารถนำก้อนที่คืนมาแล้วกลับมาใช้ซ้ำได้ ผลคือหน่วยความจำแตกกระจาย ค่า resident set size ไต่สูงขึ้นเรื่อยๆ และค้างอยู่ที่ระดับนั้นแม้ผู้โจมตีจะเลิกยิงไปนานแล้วก็ตาม

รายละเอียดช่องโหว่

ประเด็นที่ถกเถียงกันมากที่สุดคือการที่โครงการ OpenSSL ตัดสินว่านี่ไม่ใช่ช่องโหว่ด้านความปลอดภัย คำขอรวมโค้ด (pull request) ของนาย Matt Caswell ผู้เขียนแพตช์ระบุไว้ชัดเจนว่าทีมความปลอดภัยเลือกที่จะ “จัดการเรื่องนี้ในฐานะการแก้บั๊กหรือการเสริมความแข็งแกร่งเท่านั้น” ทั้งที่นโยบายความปลอดภัยของ OpenSSL เองกำหนดระดับความรุนแรงไว้ 4 ระดับตั้งแต่ Critical ลงมาถึง Low และคำว่า “bug or hardening” ไม่ได้อยู่ในนั้นเลย แม้แต่ปัญหาระดับ Low ก็ยังได้รับหมายเลข CVE บันทึกใน changelog และรายการบนหน้าช่องโหว่ แต่ HollowByte ไม่ได้รับทั้งสามอย่าง โดย The Hacker News ตรวจสอบแล้วไม่พบการกล่าวถึงการแก้ไขนี้ในบันทึกการปล่อยรุ่นหรือใน changelog ของ 4.0.1 ทั้ง 23 รายการ

เมื่อเทียบกับกรณีอื่นจะเห็นความไม่สอดคล้องชัดขึ้น เมื่อเดือนมกราคมที่ผ่านมา OpenSSL กำหนดหมายเลข CVE-2025-66199 ระดับ Low ให้กับบั๊กการบีบอัดใบรับรองใน TLS 1.3 ที่ค่าความยาวจากฝั่งตรงข้ามทำให้บัฟเฟอร์ในฮีปขยายก่อนการตรวจสอบ กินหน่วยความจำราว 22 MiB ต่อการเชื่อมต่อ แต่บั๊กนั้นต้องอาศัยเงื่อนไข 4 อย่างประกอบกัน ขณะที่ HollowByte ไม่ต้องการเงื่อนไขใดเลย และในรุ่นวันที่ 9 มิถุนายนเดียวกันนั้นเอง ก็มีการกำหนด CVE-2026-34183 ระดับ Moderate ให้กับปัญหาหน่วยความจำโตไม่จำกัดในตัวจัดการ QUIC PATH_CHALLENGE ทั้งที่ทั้งสองกรณีเป็น DoS จากการกินหน่วยความจำเหมือนกัน แต่ได้หมายเลขกันทั้งคู่ ส่วนรุ่นเดียวกันนี้ยังปิด CVE ไปอีก 18 รายการรวมถึงช่องโหว่ use-after-free ระดับ High ใน PKCS7_verify() ทำให้ผู้ที่อัปเกรดตามปกติได้รับการแก้ไขไปโดยไม่รู้ตัว

สถานการณ์ที่ยากกว่าคือฝั่งดิสทริบิวชัน เพราะค่าเริ่มต้นที่บริษัท Red Hat ระบุไว้คือการนำแพตช์มาใส่ในเวอร์ชันเดิม (backport) แทนที่จะขยับเลขเวอร์ชัน ทำให้แพ็กเกจที่แก้แล้วยังรายงานเวอร์ชันเดิมที่ใช้สร้างอยู่ ปกติสิ่งที่ช่วยคลี่คลายเรื่องนี้คือประกาศเตือนและฟีด OVAL ซึ่งทั้งคู่อ้างอิงตามชื่อ CVE แต่ในกรณีนี้ไม่มี CVE ให้อ้างอิงเลย ทางเลือกที่เหลือคือดู changelog ของแพ็กเกจหรือสอบถามผู้ดูแลโดยตรงว่าได้ปรับฐานมาที่รุ่นวันที่ 9 มิถุนายนหรือรับแพตช์เข้ามาแล้วหรือไม่ ซึ่งคือคำขอรวมโค้ดหมายเลข 30792 สำหรับสาย master และ 4.0, หมายเลข 30793 สำหรับ 3.6, 3.5 และ 3.4 และหมายเลข 30794 สำหรับ 3.0 นอกจากนี้แพตช์ยังครอบคลุมเฉพาะ TLS เท่านั้น เพราะนาย Matt Caswell เขียนไว้ในคำขอรวมโค้ดว่า DTLS ถูกปล่อยไว้เนื่องจากการแก้ให้ถูกต้องจะกระทบวงกว้างเกินไป และโครงการตัดสินใจว่ายังไม่แก้ในตอนนี้ โดย The Hacker News เปรียบเทียบซอร์สโค้ดที่แท็ก 3.6.2 และ 3.6.3 พบว่าไฟล์ที่จัดการ handshake ของ DTLS เหมือนกันทุกไบต์ และแม้แต่ใน 4.0.1 ซึ่งเป็นรุ่นล่าสุด เส้นทางนั้นก็ยังกำหนดขนาดบัฟเฟอร์จากความยาวที่ฝั่งตรงข้ามประกาศมาอยู่เช่นเดิม

ผลกระทบต่อไทย

OpenSSL เป็นไลบรารีเข้ารหัสที่อยู่เบื้องหลังเซิร์ฟเวอร์แทบทุกตัวในประเทศไทย ตั้งแต่เว็บเซิร์ฟเวอร์ NGINX และ Apache ของหน่วยงานราชการและธนาคาร ไปจนถึงอุปกรณ์เครือข่าย VPN gateway ระบบอีเมล และอุปกรณ์ฝังตัวจำนวนมาก การที่ช่องโหว่นี้ถูกโจมตีได้โดยไม่ต้องยืนยันตัวตนและใช้ข้อมูลเพียง 11 ไบต์ หมายความว่าผู้โจมตีรายเดียวที่มีแบนด์วิดท์จำกัดก็สามารถทำให้บริการสาธารณะล่มได้ โดยไม่ต้องอาศัยบอตเน็ตขนาดใหญ่แบบการโจมตี DDoS ทั่วไป

ปัญหาที่หนักที่สุดสำหรับองค์กรไทยคือการที่ไม่มีหมายเลข CVE ให้อ้างอิง เพราะกระบวนการบริหารช่องโหว่ของหน่วยงานส่วนใหญ่ผูกอยู่กับผลสแกนจากเครื่องมืออัตโนมัติและประกาศเตือนตามหมายเลข CVE เมื่อไม่มีทั้งสองอย่าง เซิร์ฟเวอร์ที่มีช่องโหว่จะผ่านการตรวจสอบตามรอบไปโดยไม่มีใครสังเกต และรายงานการปฏิบัติตามมาตรฐานก็จะแสดงผลว่าปลอดภัยทั้งที่ยังเสี่ยงอยู่ นอกจากนี้อาการที่เกิดขึ้นคือหน่วยความจำค่อยๆ ไต่ขึ้นแล้วโปรเซสถูกฆ่า ซึ่งทีมปฏิบัติการมักตีความว่าเป็นปัญหาด้านสมรรถนะหรือหน่วยความจำรั่วของแอปพลิเคชันเอง ทำให้แก้ปัญหาผิดทางด้วยการเพิ่ม RAM หรือตั้งให้รีสตาร์ตอัตโนมัติ แทนที่จะมองว่าเป็นการถูกโจมตี

คำแนะนำ

หากองค์กรคอมไพล์ OpenSSL เอง ควรอัปเกรดเป็นรุ่นที่ระบุไว้คือ 4.0.1, 3.6.3, 3.5.7, 3.4.6 หรือ 3.0.21 แล้วรีสตาร์ตทุกบริการที่โหลดไลบรารีรุ่นเก่าอยู่ เพราะการอัปเดตไฟล์ไลบรารีเพียงอย่างเดียวไม่มีผลกับโปรเซสที่กำลังทำงานและยังคงใช้โค้ดเดิมในหน่วยความจำ ส่วนองค์กรที่ใช้แพ็กเกจจากดิสทริบิวชัน ควรตรวจสอบ changelog ของแพ็กเกจหรือสอบถามผู้ดูแลโดยตรงว่าได้ปรับฐานมาที่รุ่นวันที่ 9 มิถุนายน 2569 หรือรับแพตช์ตามคำขอรวมโค้ดหมายเลข 30792, 30793 หรือ 30794 เข้ามาแล้วหรือไม่ เนื่องจากไม่สามารถพึ่งพาเครื่องมือสแกนตามหมายเลข CVE ได้ในกรณีนี้

ในระหว่างที่ยังอัปเดตไม่ได้ ควรตั้งการเฝ้าระวังค่า resident set size ของโปรเซสที่ให้บริการ TLS และตั้งการแจ้งเตือนเมื่อหน่วยความจำไต่ขึ้นต่อเนื่องโดยที่จำนวนการเชื่อมต่อไม่ได้เพิ่มตาม ซึ่งเป็นลายเซ็นเฉพาะของการโจมตีรูปแบบนี้ พร้อมทั้งพิจารณาตั้งเวลาหมดอายุของกระบวนการจับมือ (handshake timeout) ให้สั้นลงเพื่อตัดการเชื่อมต่อที่ค้างรอเนื้อหาเร็วขึ้น และวางอุปกรณ์ยุติ TLS หรือ reverse proxy ที่แพตช์แล้วไว้ด้านหน้าเซิร์ฟเวอร์ที่ยังอัปเดตไม่ได้ ทั้งนี้พึงระวังว่าการจำกัดจำนวนการเชื่อมต่อต่อ IP เพียงอย่างเดียวไม่เพียงพอ เพราะการโจมตีนี้สร้างความเสียหายได้โดยไม่ต้องแตะเพดานการเชื่อมต่อ สุดท้ายควรจดบันทึกไว้ว่าเส้นทาง DTLS ยังไม่ได้รับการแก้ไข องค์กรที่ให้บริการผ่าน DTLS เช่น VPN บางรูปแบบหรือ WebRTC ควรเฝ้าระวังเป็นพิเศษต่อไป

แหล่งอ้างอิง