สรุปสั้น
OpenSSH คือ ซอฟต์แวร์ SSH ที่ใช้เข้าระบบ Linux จากระยะไกลแทบทุกเครื่อง ส่วน Alpine Linux คือ distro ขนาดเล็กที่นิยมใช้ในคอนเทนเนอร์และคลาวด์ ซึ่งสร้างบนไลบรารีภาษา C ชื่อ musl แทน glibc เมื่อวันที่ 5 พฤศจิกายน 2569 โครงการ OpenSSH ออกเวอร์ชัน 10.6p2 แบบเร่งด่วนเพื่อปิดช่องโหว่ที่จัดระดับวิกฤต ช่องโหว่นี้ให้ผู้โจมตีล็อกอินบัญชีที่ไม่ได้ตั้งรหัสผ่าน เช่น บัญชีที่ใช้ SSH key อย่างเดียว บนเซิร์ฟเวอร์ Alpine ที่รันแพ็กเกจ openssh-server มาตรฐานได้ ผู้โจมตีต้องเข้าถึงเซิร์ฟเวอร์ทางเครือข่าย รู้ชื่อบัญชี และส่งรหัสผ่านยาว 257 ถึง 1,024 ไบต์ การโจมตีสำเร็จทุกครั้งด้วยการเชื่อมต่อเดียว
ต้นเหตุ คือ เมื่อรหัสผ่านยาวเกิน 256 ไบต์ ฟังก์ชัน crypt() ของ musl จะคืนค่า “” เพื่อบอกว่าผิดพลาด และค่านั้นบังเอิญตรงกับ “” ที่เก็บแทนรหัสผ่านของบัญชีที่ไม่มีรหัสผ่าน sshd จึงยอมให้ล็อกอิน ระบบที่ไม่ใช่ Linux, Linux บน glibc และระบบที่ตรวจรหัสผ่านผ่าน PAM ไม่ได้รับผล ยังไม่มีรายงานการโจมตีจริงและยังไม่มี CVE นาย Damien Miller จากโครงการ OpenSSH สั่งให้ผู้ใช้ระบบที่ได้รับผลตั้ง PasswordAuthentication=no หรือปิด SSH “ทันที” ถ้ายังอัปเดตไม่ได้
รายละเอียดข่าว
เว็บไซต์ The Hacker News รายงานเมื่อวันที่ 5 พฤศจิกายน 2569 ว่า Alpine ออกแพ็กเกจที่แก้แล้วให้ทุกรุ่นย้อนไปถึง 3.16 รวมถึงสาขา 3.16 ถึง 3.21 ที่หมดการสนับสนุนแล้ว และ point release 3.21.10, 3.22.8, 3.23.8 และ 3.24.4 มีแพ็กเกจที่แก้แล้วในตัว ผู้รายงาน คือ นาย Özgün Kültekin จาก Wakefield ซึ่งระบุว่า OpenWrt, Buildroot และ Yocto เป็นระบบบน musl อื่นที่ควรตรวจ OpenWrt ใช้ Dropbear เป็นค่าเริ่มต้นซึ่งไม่ได้รับผล ช่องโหว่จึงมีผลบน OpenWrt เฉพาะเมื่อผู้ดูแลติดตั้ง OpenSSH server เอง
ทีมของ Miller รู้เรื่องช่องโหว่ต้นสัปดาห์และออกแพตช์เร็วที่สุดเท่าที่ทำได้ Miller ระบุในประกาศว่าทีมมองว่าการปิดข่าวช่องโหว่นานเป็นอันตรายและช่วยผู้โจมตีเป็นหลัก เพราะช่วงหลังเห็นเอเจนต์ AI ค้นพบบั๊กเดียวกันซ้ำ บางครั้งภายในไม่กี่ชั่วโมง ข้อจำกัดของข้อมูล คือ ยังไม่มีหมายเลข CVE ณ วันที่รายงาน และยังไม่มีรายงานการโจมตีจริง
รายละเอียดช่องโหว่
เซิร์ฟเวอร์จะเสี่ยงเมื่อเข้าเงื่อนไขครบ 4 ข้อ — ตามประกาศของ Alpine ข้อแรก คือ รันแพ็กเกจ openssh-server ที่สร้างโดยไม่มี PAM หรือรัน openssh-server-pam แต่ตั้ง UsePAM no ข้อสอง คือ PasswordAuthentication เป็น yes ซึ่งเป็นค่าเริ่มต้นของ OpenSSH ข้อสาม คือ มีบัญชีที่ช่องรหัสผ่านเป็น “*” คือ ไม่ได้ตั้งรหัสผ่าน และข้อสี่ คือ มีบัญชีอื่นอย่างน้อยหนึ่งบัญชีที่ hash รหัสผ่านขึ้นต้นด้วย $5$ หรือ $6$ บัญชีที่มีรหัสผ่านเพียงบัญชีเดียวก็ทำให้ทุกบัญชีที่ไม่มีรหัสผ่านเสี่ยง
บัญชีที่ไม่มีรหัสผ่านบน Alpine มีมากกว่าที่คิด — ได้แก่ ผู้ใช้ที่ใช้แค่ key ซึ่งสร้างด้วย adduser โดยไม่ตั้งรหัสผ่านหรือด้วย usermod -p ‘’ ผู้ใช้จาก directory service ผ่าน musl-nscd ซึ่งไม่มี shadow entry, root ที่มาเป็น root: ใน base image ตั้งแต่ราว Alpine 3.16 และผู้ใช้ alpine ใน cloud image ทางการที่สร้างด้วย tiny-cloud root ได้รับการป้องกันจากค่าเริ่มต้น PermitRootLogin prohibit-password แต่ป้องกันไม่ได้ถ้าบัญชีที่โดนเปลี่ยนเป็น root ได้ เช่น ผ่าน doas
กรณี tiny-cloud ที่กลายเป็น root ได้ — image tiny-cloud รุ่น 3.18.11 ถึง 3.24.3 ให้ผู้ใช้ alpine ใช้ doas ได้โดยไม่ต้องใส่รหัสผ่าน เครื่องปลอดภัยตอนบูตครั้งแรก แต่จะเปิดรับการโจมตีทันทีที่มี hash แบบ $6$ ในเครื่อง เช่น หลังผู้ดูแลตั้งรหัสผ่านคอนโซล ผู้โจมตีจึงล็อกอินเป็น alpine แล้วใช้ doas เป็น root ได้
ทำไมรหัสผ่านยาวถึงผ่าน — เมื่อไม่ใช้ PAM sshd ตรวจรหัสผ่านเอง โดยให้ crypt() แปลงรหัสผ่านที่ส่งมาเป็น hash แล้วเทียบกับค่าที่เก็บไว้ บัญชีที่ไม่มีรหัสผ่านมีแค่ “” ซึ่งสั้นเกินกว่าจะมี salt (ค่าสุ่มนำหน้า hash) sshd จึงยืม salt ของบัญชีอื่นที่มี hash จริง สำหรับ hash แบบ $5$ และ $6$ crypt() ของ musl ปฏิเสธรหัสผ่านยาวเกิน 256 ไบต์และคืนค่า “” เป็นสัญญาณผิดพลาด ค่านั้นตรงกับ “*” ที่เก็บไว้ sshd จึงยอมให้ล็อกอิน ส่วนขอบบน 1,024 ไบต์ คือ ขีดจำกัดความยาวรหัสผ่านของ sshd เอง
ที่มาของบั๊กย้อนไปหลายปี — พฤติกรรมของ musl มาจากการเปลี่ยนแปลงเมื่อ 9 สิงหาคม 2555 ที่ให้ crypt() คืน “hash ที่จับคู่ไม่ได้” แทน NULL เพราะหลายโปรแกรมไม่ตรวจความผิดพลาด และขีดจำกัด 256 ไบต์ตามมาเมื่อ 29 สิงหาคม 2555 เพื่อกันการโจมตีแบบ DoS ส่วนการยืม salt มาจากการแก้ CVE-2016-6210 ของ OpenSSH เมื่อ 15 กรกฎาคม 2559 ซึ่งเคยให้ผู้โจมตีรู้ว่าชื่อผู้ใช้ใดมีอยู่จริง Kültekin ระบุว่าปัญหามีมาตั้งแต่ตอนนั้น โค้ดใน 10.6p2 ให้ sshd ปฏิเสธการจับคู่เมื่อค่าที่เก็บสั้นกว่า 4 ตัวอักษร ซึ่ง OpenSSH เรียกว่าทางแก้ชั่วคราว เพราะต้นเหตุอยู่นอก sshd
กรณีที่ไม่ได้รับผล — คอนเทนเนอร์ที่ไม่ได้รัน sshd ระบบที่ตั้ง PasswordAuthentication no cloud image ที่ตั้งค่าผ่าน cloud-init ซึ่งเขียนค่านี้ไว้ บัญชีที่ล็อกด้วย ! ใน /etc/shadow และเครื่องที่ไม่มีบัญชีใดมี hash แบบ $
ผลกระทบ
กลุ่มที่เสี่ยงที่สุด คือ เซิร์ฟเวอร์และ VM ที่รัน Alpine พร้อม openssh-server แบบค่าเริ่มต้นและเปิด SSH สู่อินเทอร์เน็ต โดยเฉพาะเครื่องที่สร้างจาก tiny-cloud image แล้วผู้ดูแลตั้งรหัสผ่านคอนโซลภายหลัง เพราะผู้โจมตีไปถึง root ได้ผ่าน doas นอกจากนี้ยังรวมอุปกรณ์ฝังตัวบน Buildroot, Yocto หรือ OpenWrt ที่ติดตั้ง OpenSSH แทน Dropbear
ผลลัพธ์เมื่อโดน คือ ผู้โจมตีได้เชลล์บนเครื่องโดยไม่ต้องรู้รหัสผ่านหรือมี key การโจมตีสำเร็จทุกครั้งและทำได้ด้วยการเชื่อมต่อเดียว จึงแทบไม่มีสัญญาณแบบ brute force ให้จับ ชื่อบัญชีที่ต้องรู้ เช่น root หรือ alpine ก็เดาได้ง่าย ความเร่งด่วนจึงสูงมาก แม้ยังไม่มีรายงานการโจมตี เพราะรายละเอียดเปิดเผยครบแล้ว
คำแนะนำ
- ทำทันที (Alpine): อัปเดตแพ็กเกจด้วย
apk upgrade -U -aแล้วรีสตาร์ต sshd ด้วยrc-service sshd restartเพราะการอัปเกรดแพ็กเกจไม่รีสตาร์ต sshd ที่รันอยู่ - ทำทันที (ยังอัปเดตไม่ได้): ตรวจก่อนว่าล็อกอินด้วย SSH key ได้ และเปิดเซสชันเดิมค้างไว้ จากนั้นตั้ง
PasswordAuthentication noในไฟล์ drop-in ใต้ /etc/ssh/sshd_config.d และในทุกบรรทัดของ /etc/ssh/sshd_config รวมถึงใน Match block ตรวจด้วยsshd -tแล้วรีสตาร์ต sshd และยืนยันว่าsshd -T | grep -i passwordauthenticationแสดง passwordauthentication no - ผู้ที่คอมไพล์ OpenSSH เอง: อัปเดตเป็น 10.6p2 และตรวจระบบบน musl อื่น เช่น Buildroot, Yocto และ OpenWrt ที่ติดตั้ง OpenSSH server
- ตรวจว่าโดนแล้วหรือยัง: ค้น /var/log/messages หาบรรทัด sshd ที่เขียนว่า Accepted password สำหรับบัญชีที่ไม่มีรหัสผ่าน เช่น alpine, root หรือผู้ใช้ที่ใช้แค่ key และบนเครื่องที่เสี่ยงให้ตรวจการใช้ doas ผู้ใช้ที่สร้างใหม่ ไฟล์ และ authorized_keys
- ถ้าตัดความเป็นไปได้ไม่ได้: ถือว่าเครื่องถูกยึดตามที่ประกาศของ Alpine แนะนำ แล้วสร้างใหม่จากแหล่งที่สะอาด
- ระยะยาว: ปิด password authentication บนเซิร์ฟเวอร์ที่เปิด SSH สู่อินเทอร์เน็ตเป็นมาตรฐาน และล็อกบัญชีที่ไม่ใช้รหัสผ่านด้วย ! แทน *
