วิเคราะห์ 0day ของ WebP
(blog.isosceles.com)- การแก้ไขด้านความปลอดภัยเพียงรายการเดียว CVE-2023-4863 ที่รวมอยู่ในอัปเดตเสถียรของ Chrome คือช่องโหว่ heap buffer overflow ในไลบรารีภาพ WebP และ Google ระบุแล้วว่ามีเอ็กซ์พลอยต์ที่ถูกใช้งานจริงอยู่แล้ว
- เมื่อพิจารณาร่วมกับรายงานของ Apple SEAR เมื่อวันที่ 6 กันยายน 2023, CVE-2023-41064 ของ Apple และร่องรอยของ BLASTPASS จาก Citizen Lab ก็มีความเป็นไปได้สูงว่าเป็นบั๊กเดียวกัน
- มีการวิเคราะห์ว่าช่องโหว่นี้เกิดจากปัญหาที่สามารถเขียนเกินขนาดบัฟเฟอร์ที่คำนวณไว้ล่วงหน้าได้ ระหว่างกระบวนการสร้าง ตาราง Huffman ของ VP8L ซึ่งเป็นการบีบอัดแบบไม่สูญเสียข้อมูลของ WebP
- เหตุผลที่ฟัซซิงทั่วไปอาจพลาดคือ ต้องสร้างทั้งตาราง Huffman ขนาดสูงสุดหลายชุดและตารางที่ไม่ถูกต้องเฉพาะแบบตามลำดับ จึงมี เงื่อนไขการทริกเกอร์ที่ซับซ้อนมาก
- แพตช์ของ upstream libwebp ดูเพียงพอแล้ว แต่เนื่องจาก libwebp ถูกใช้อย่างกว้างขวางในเบราว์เซอร์ ระบบปฏิบัติการ และแอปต่าง ๆ การ กระจายแพตช์ และการทำ sandboxing จึงสำคัญ
เหตุใดแพตช์ของ Chrome จึงเชื่อมโยงกับ BLASTPASS
- Google ได้แก้ไข CVE-2023-4863 ที่ Apple Security Engineering and Architecture (SEAR) รายงานไว้ ในอัปเดตเสถียรของ Chrome ช่วงต้นเดือนกันยายน 2023
- ช่องโหว่นี้คือ heap buffer overflow ในไลบรารีภาพ WebP
- Google ระบุว่าทราบว่า “มีเอ็กซ์พลอยต์ของ CVE-2023-4863 อยู่จริงในสภาพแวดล้อมการใช้งานจริง”
- ในช่วงเวลาใกล้กัน Citizen Lab ตรวจพบพฤติกรรมน่าสงสัยใน iPhone ของบุคคลที่สังกัดองค์กรภาคประชาสังคมในกรุงวอชิงตัน ดี.ซี.
- BLASTPASS เชื่อมโยงกับกรณีที่ใช้เอ็กซ์พลอยต์ zero-click zero-day ของ iMessage เพื่อแจกจ่ายสปายแวร์ Pegasus ของ NSO Group
- หลังจาก Citizen Lab ส่งผลการวิเคราะห์ทางเทคนิคให้ Apple แล้ว Apple ก็เปิดเผย CVE สองรายการในประกาศความปลอดภัยวันที่ 7 กันยายน
- CVE แรกของ Apple คือ CVE-2023-41061 ซึ่งสอดคล้องกับร่องรอยของการผูกเอ็กซ์พลอยต์ภาพเข้ากับไฟล์แนบ PassKit เพื่อข้าม sandbox BlastDoor ของ iMessage
- ภาพอันตรายน่าจะถูกประมวลผลในอีกโปรเซสหนึ่งที่ไม่มี sandbox
- CVE ที่สองคือ CVE-2023-41064 ซึ่งเป็นช่องโหว่ buffer overflow ใน Apple ImageIO
- ImageIO คือเฟรมเวิร์กสำหรับพาร์สภาพของ Apple ที่ใช้ตรวจสอบรูปแบบภาพหลายชนิดและเชื่อมไปยังดีโคเดอร์ที่เหมาะสม
- เนื่องจากไม่มีรายละเอียดทางเทคนิค จึงยังยืนยันไม่ได้ว่า CVE-2023-41064 กระทบกับรูปแบบภาพชนิดใด
- เมื่อพิจารณาว่า Apple เพิ่งเพิ่มการรองรับ WebP ใน ImageIO, ทีมความปลอดภัยของ Apple รายงานช่องโหว่ WebP ให้ Chrome เมื่อวันที่ 6 กันยายน และ Google ออกแพตช์ฉุกเฉินภายใน 5 วันพร้อมระบุว่ามีการใช้งานจริง จึงมีความเป็นไปได้สูงว่า BLASTPASS และ CVE-2023-4863 เป็นบั๊กเดียวกัน
ตำแหน่งของช่องโหว่ที่แพตช์ libwebp ชี้ให้เห็น
- เมื่อนำ bug ID ในประกาศความปลอดภัยของ Chrome มาเทียบกับคอมมิตโอเพนซอร์สของ libwebp จะพบว่าแพตช์ Fix OOB write in BuildHuffmanTable ตรงกับ CVE-2023-4863
- แพตช์นี้ถูกสร้างขึ้นในวันที่ 7 กันยายน 2023 ซึ่งเป็นวันถัดจากที่ Apple รายงาน
- ช่องโหว่อยู่ใน VP8L ซึ่งเป็นส่วนรองรับการบีบอัดแบบไม่สูญเสียข้อมูลของ WebP
- การบีบอัดแบบไม่สูญเสียข้อมูลของ WebP ใช้ Huffman coding เพื่อเก็บและกู้คืนพิกเซลได้อย่างถูกต้อง 100%
- อิมพลีเมนเทชันสมัยใหม่ใช้ตารางแทนโครงสร้างต้นไม้เชิงแนวคิดเพื่อเพิ่มประสิทธิภาพการดีโค้ด
- เวอร์ชันที่มีช่องโหว่จะจองหน่วยความจำด้วย ขนาดบัฟเฟอร์ที่คำนวณไว้ล่วงหน้า จากตารางคงที่ แล้วสร้างตาราง Huffman ลงในพื้นที่นั้นโดยตรง
- เวอร์ชันใหม่เปลี่ยนเป็นคำนวณขนาดรวมที่ต้องใช้สำหรับตารางผลลัพธ์ในพาสแรก โดยยังไม่เขียนจริง
- หากขนาดรวมมากกว่าบัฟเฟอร์ที่คำนวณไว้ล่วงหน้า ก็จะสร้างการจัดสรรหน่วยความจำที่ใหญ่ขึ้น
- โฟลว์หลักอยู่ที่
huffman_tablesซึ่งถูกจัดสรรในReadHuffmanCodesของsrc/dec/vp8l_dec.cและการเรียกVP8LBuildHuffmanTable/BuildHuffmanTableภายในReadHuffmanCode- ตาราง Huffman ถูกแบ่งเป็น 5 เซกเมนต์ที่มีขนาด alphabet ต่างกัน
- หากต้องการทำให้เกิด overflow จำเป็นต้องจัดรูปทั้ง 5 ตารางนี้อย่างละเอียด
กระบวนการสร้างไฟล์ทริกเกอร์
- การบีบอัดแบบไม่สูญเสียข้อมูลของ WebP จะวิเคราะห์ความถี่ของพิกเซลอินพุต แล้วกำหนดบิตสตริงสั้นให้ค่าที่พบบ่อย และบิตสตริงยาวให้ค่าที่พบน้อย
- โค้ดถูกจัดให้ดีโคเดอร์สามารถแยกความยาวของบิตสตริงได้เสมอ
- ภาพที่ถูกบีบอัดจึงต้องมีข้อมูลสถิติและข้อมูลการกำหนดโค้ดเพื่อให้สามารถสร้างแมปปิงระหว่างโค้ดกับค่ากลับมาได้
- WebP ยังบีบอัดตัวตาราง Huffman เองด้วย Huffman coding เพื่อลดขนาดไฟล์
- โครงสร้างนี้ทำให้การวิเคราะห์และการทริกเกอร์ช่องโหว่ซับซ้อนขึ้น
@mistymntncopได้จัดเตรียมโค้ดฮาร์เนสสำหรับสร้าง WebP รูปแบบถูกต้องที่มีข้อมูล Huffman coding ตามต้องการ หรือก็คือมี code lengths ตามต้องการ- ด้วยฮาร์เนสนี้จึงสามารถส่งอาร์เรย์
code_lengthsใดก็ได้ไปยังการเรียกBuildHuffmanTableเป้าหมาย
- ด้วยฮาร์เนสนี้จึงสามารถส่งอาร์เรย์
- ในการทดลองด้วยมือ พบว่าปฏิสัมพันธ์ระหว่าง histogram ภายใน
BuildHuffmanTable,num_open,num_nodesและค่าkeyที่ใช้ติดตามตำแหน่งเริ่มของReplicateValueนั้นซับซ้อนมาก- root table ตั้งแต่
count[0]ถึงcount[8]ไม่ได้ส่งผลโดยตรงมากนักต่อtotal_sizeแต่สามารถเปลี่ยนสถานะภายในในภายหลังได้ - second level tables ตั้งแต่
count[9]ถึงcount[15]มีผลโดยตรงต่อtotal_sizeสุดท้าย
- root table ตั้งแต่
- enough.c ของ Mark Adler จะแสดง histogram ของ lookup table สำหรับต้นไม้ Huffman สูงสุดที่เป็นไปได้ ตามขนาด alphabet, ขนาด root table และความยาวโค้ดสูงสุด
- มีคอมเมนต์ระบุว่า
kTableSizeของ libwebp ถูกคำนวณจากเครื่องมือนี้ - ด้วยเครื่องมือนี้สามารถสร้างขนาดบัฟเฟอร์ที่คำนวณไว้ล่วงหน้าขึ้นมาใหม่ได้ และยังยืนยันได้ด้วยเครื่องมือของ
@mistymntncopว่า code lengths ที่ “enough” สร้างขึ้นสามารถเติมการจัดสรรhuffman_tablesได้ครบ 100%
- มีคอมเมนต์ระบุว่า
เงื่อนไขที่ทำให้เกิด overflow จริง
- เครื่องมือ
enoughคำนวณค่าสูงสุดสำหรับ โค้ดที่ถูกต้องและสมบูรณ์- สำหรับหนึ่งในตารางขนาดเล็กที่มีขนาดสัญลักษณ์ 40, root table 8 บิต และความยาวโค้ดสูงสุด 15 ขนาดสูงสุดคือ 410
- ไม่พบกรณีที่โค้ดซึ่ง
BuildHuffmanTableมองว่าถูกต้อง จะสร้างขนาดเกิน 410
- overflow ไม่ได้เกิดจากการใช้ต้นไม้ Huffman ที่ถูกต้องล้วน ๆ แต่เกิดเมื่อใส่ต้นไม้ Huffman ที่ไม่ถูกต้องในขั้นตอนสุดท้าย
- เริ่มจากสร้างตารางผลลัพธ์ขนาดสูงสุดก่อนด้วยต้นไม้ Huffman ที่ถูกต้อง 4 ต้น
- เมื่อใส่ต้นไม้ Huffman ที่ไม่ถูกต้องลงในตารางสุดท้าย
ReplicateValueจะสามารถเขียนออกนอกขอบเขตได้ก่อนถึงการตรวจสอบความสอดคล้องขั้นสุดท้าย
- วิธีทำซ้ำคือ checkout คอมมิต libwebp ที่มีช่องโหว่
7ba44f80f3b94fc0138db159afea770ef06532a0เปิด AddressSanitizer แล้วใช้โค้ด PoC ของ@mistymntncopสร้างbad.webpเพื่อดีโค้ดด้วยdwebp- AddressSanitizer รายงาน
heap-buffer-overflowในBuildHuffmanTable - การเขียนที่รายงานเกิดขึ้นที่ตำแหน่งถัดจากพื้นที่ขนาด 11816 ไบต์ทันที
- AddressSanitizer รายงาน
- มีอินพุตหลายแบบที่สามารถทำให้
huffman_tablesoverflow ได้- ใน code lengths ที่ค้นพบ มีกรณีที่เขียนเลยท้ายการจัดสรร
huffman_tablesไปได้ถึง 400 ไบต์ - แม้การควบคุมค่าที่เขียนได้จะเป็นเพียงบางส่วน แต่ก็ดูยังสามารถเอ็กซ์พลอยต์ได้
- ใน code lengths ที่ค้นพบ มีกรณีที่เขียนเลยท้ายการจัดสรร
- ต้นไม้ Huffman ของอินพุตที่ไม่ถูกต้องมีความไม่สมดุลบางส่วน และในช่วงหนึ่งของกิ่งที่ไม่สมดุลมี internal node จำนวนมากที่ไม่มีลูก
- โครงสร้างนี้ทำให้เกิดดัชนี
keyที่ต้นไม้แบบถูกต้องไม่สามารถไปถึงได้
- โครงสร้างนี้ทำให้เกิดดัชนี
วิธีที่แพตช์ป้องกัน overflow
- ในตอนแรก แพตช์ดูเหมือนจะป้องกัน heap overflow ด้วยการขยายบัฟเฟอร์แบบไดนามิกให้พอดีกับขนาดที่ต้องใช้
- แต่จริง ๆ แล้วพาสแรกของเวอร์ชันที่แพตช์แล้วจะรัน
BuildHuffmanTableเพื่อคำนวณขนาดรวมที่ต้องใช้ โดยไม่เขียนลงตาราง- อินพุตที่ไม่ถูกต้องซึ่งเคยทำให้เกิด overflow จะทำให้
BuildHuffmanTableล้มเหลวและคืนค่า 0 ในพาสแรกนี้ - เนื่องจากพาสแรกไม่มีการเขียน แม้จะมีการประมวลผลต้นไม้ที่ไม่ถูกต้องเพียงบางส่วน ก็จะไม่เกิดการเขียนออกนอกขอบเขต
- อินพุตที่ไม่ถูกต้องซึ่งเคยทำให้เกิด overflow จะทำให้
- เพราะยังไม่พบกรณีของโค้ดที่ถูกต้องและสมบูรณ์ซึ่งทำให้เกิด overflow แบบเดียวกัน แพตช์นี้จึงดูเพียงพอ
เหตุผลที่ฟัซซิงอาจพลาดได้ง่าย
- libwebp ถูกฟัซผ่าน Google OSS-Fuzz มานาน และส่วนรองรับ WebP แบบไม่สูญเสียข้อมูลก็ถูกฟัซอย่างกว้างขวางด้วย
- ปัญหาหลักคือทั้งฟอร์แมตและเงื่อนไขการทริกเกอร์มีความซับซ้อน
- จากความเป็นไปได้ระดับหลายหมื่นล้านแบบ ต้องสร้างตาราง Huffman ขนาดสูงสุด 4 ตารางก่อนสำหรับขนาด alphabet 280 และ 256
- จากนั้นต้องสร้างตาราง Huffman ที่ไม่ถูกต้องซึ่งมีรูปแบบเฉพาะมาก สำหรับขนาด alphabet 40
- หากผิดไปเพียง 1 บิตในขั้นตอนไหนก็ตาม ดีโคเดอร์ภาพจะเกิดข้อผิดพลาดและจบการทำงานอย่างปลอดภัย
- หลังจากแก้ 0day ของ WebP แล้ว Google ได้ปล่อยฟัซเซอร์ใหม่ที่เจาะจงกับรูทีน Huffman ของ WebP
- แต่แม้จะรันฟัซเซอร์ดังกล่าวก็ยังไม่พบ CVE-2023-4863
- ทั้งการกลายพันธุ์แบบ bit flip มาตรฐาน ลูปป้อนกลับจาก code coverage และแนวทางอิงสถานะอินพุตอย่าง CmpLog ของ AFL++ ต่างก็ยากที่จะผ่านสถานะกึ่งกลางไปจนถึงสถานะสุดขั้วนี้ได้
- เทคนิค dynamic symbolic execution อย่าง TritonDSE ของ Quarkslab อาจมีโอกาส แต่ยังไม่ได้รับการยืนยัน
- ช่องโหว่ Load_SBit_Png ของ FreeType มีลักษณะต่างออกไป
- ในกรณี Load_SBit_Png นั้น พลาดการค้นพบเพราะฟัซซิงฮาร์เนสไม่สะท้อนรูปแบบการใช้ API ได้เพียงพอ
- ส่วน CVE-2023-4863 ใกล้เคียงกับกรณีที่ฟัซได้ยากเพราะข้อจำกัดของช่องโหว่เอง มากกว่าจะเป็นเพราะฮาร์เนสไม่เพียงพอ
ขอบเขตผลกระทบและสถานะการรับมือ
- Citizen Lab จับเอ็กซ์พลอยต์ขั้นสูงที่ถูกใช้งานจริงได้ และดูเหมือนว่า Apple กับ Chrome จะกระจายอัปเดตไปยังผู้ใช้หลายพันล้านคนภายในไม่กี่วัน
- ในเวลานั้น Android ยังมีโอกาสได้รับผลกระทบอยู่
- BitmapFactory ของ Android ทำหน้าที่ดีโค้ดภาพคล้ายกับ Apple ImageIO และรองรับ libwebp
- ในขณะนั้นประกาศความปลอดภัยของ Android ยังไม่รวมการแก้ CVE-2023-4863 แต่ตัวแก้ไขถูก merge เข้า AOSP แล้ว
- หาก Android ได้รับผลกระทบ ก็อาจลามไปสู่การเอ็กซ์พลอยต์ระยะไกลในแอปอย่าง Signal หรือ WhatsApp ได้
- คาดว่าจะมีการแก้ไขในประกาศความปลอดภัยเดือนตุลาคม
- แพตช์ของ upstream libwebp ดูเหมือนถูกนำไปใช้ได้อย่างถูกต้อง และกำลังกระจายไปยังจุดที่จำเป็น
- เนื่องจาก libwebp ถูกใช้งานในหลายแห่ง การกระจายแพตช์ให้ครอบคลุมเพียงพออาจต้องใช้เวลา
- สำหรับโค้ดพาร์เซอร์ที่ซับซ้อนและอยู่ใกล้พื้นผิวการโจมตีแบบ zero-click remote exploit อย่างการดีโค้ดภาพ การพึ่งพาฟัซซิงอย่างเดียวอาจไม่สามารถรับประกันความปลอดภัยได้ จึงต้องลงทุนกับ การตรวจทานซอร์สโค้ดเชิงรุก และ sandboxing ที่เหมาะสม
ความไม่สมดุลของการเปิดเผยข้อมูลทางเทคนิค
- หากผู้ขายไม่เปิดเผยรายละเอียดทางเทคนิคอย่างเพียงพอ ผู้ป้องกันจะตรวจสอบผลกระทบของช่องโหว่ได้ยากขึ้น
- ผู้โจมตีมีแรงจูงใจสูงในการติดตามและเอ็กซ์พลอยต์ช่องโหว่ N-day และการไม่เปิดเผยรายละเอียดก็ไม่ได้ทำให้พวกเขาช้าลงมากนัก
- ฝ่ายป้องกันมักไม่มีทรัพยากรเพียงพอที่จะทำการวิเคราะห์ทางเทคนิคระดับนี้
- หากปกปิดแม้แต่ข้อมูลพื้นฐานของพฤติกรรมการโจมตี ก็จะเกิดความไม่สมดุลที่ทำให้ผู้โจมตีมีความเข้าใจเกี่ยวกับช่องโหว่และเอ็กซ์พลอยต์มากกว่าฝ่ายป้องกัน
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
บั๊กนี้ดูคล้ายกับ บั๊ก Timsort เมื่อปี 2015 มากที่สุด [1]
Timsort เป็นอัลกอริทึมเรียงลำดับแบบไฮบริดที่ชาญฉลาดซึ่งมาจาก CPython และ implementation หลายตัวรวมถึง OpenJDK ก็นำไปใช้ในลักษณะแทบจะเป็นการแปลโค้ดต้นฉบับระดับซอร์ส มันรักษา stack ของ run ที่เรียงลำดับแล้ว และมีการพิสูจน์ว่าตามโครงสร้างแล้วมีขอบเขตบนแบบจำกัดที่เล็กพอสำหรับขนาด stack สูงสุดที่เป็นไปได้ แต่ implementation ดั้งเดิมของ CPython ไม่ตรงกับการพิสูจน์อย่างพอดี ทำให้เกิด stack overflow ได้ในกรณีหายาก ดังนั้นใน CPython จึงเป็นบั๊กความปลอดภัยร้ายแรง แต่ใน Java กรณีนั้นจะ throw exception จึงไม่ใช่ปัญหาความปลอดภัยแบบเดียวกันใน OpenJDK
ในทำนองเดียวกัน บั๊ก WebP ครั้งนี้ก็เกิดจากการที่ขนาดตารางสูงสุดถูกพิสูจน์อย่างเป็นทางการแล้ว แต่ไม่ตรงกับค่าที่อยู่ในซอร์สโค้ดจริง บั๊กแบบนี้ทั้งตรวจสอบและรีวิวยาก มีการพิสูจน์อยู่ และซอร์สก็ดูเหมือนจะตรงกับการพิสูจน์ จึงคิดได้ง่ายว่าไม่น่ามีปัญหา เรื่องนี้ดูเป็นสัญญาณชัดว่าจำเป็นต้องมี formal verification ที่เข้าถึงได้มากกว่าการรีวิวโดยคน และต้องใช้ภาษาที่ memory-safe มากขึ้น type system ก็ถือได้ว่าเป็น formal verification รูปแบบอ่อนอย่างหนึ่ง
[1] http://envisage-project.eu/wp-content/uploads/2015/02/sortin...
https://github.com/google/wuffs
อาจเขียน check แบบเดียวกันอย่างชัดเจนเพื่อให้ผ่านข้อกำหนดนี้ก็ได้ แต่ถ้าเคยเชื่อว่าเป็นซอฟต์แวร์ประสิทธิภาพสูงเลยไม่จำเป็นต้องมี check จุดที่เครื่องมือ WUFFS ไม่ยอมรับโค้ดก็น่าจะทำให้พบว่าความเชื่อนั้นผิด แม้จะอ่อนกว่า formal verification แบบสมบูรณ์ แต่ในแง่เป้าหมายเรื่องความปลอดภัยของโปรแกรมถือว่าดีขึ้นมาก และดีกว่าการที่คนบอก “LGTM” มาก
ในบทความนี้มีหลายส่วนที่น่าสนใจนอกเหนือจากคำถามว่า “ตอนนี้ต้องแพตช์อะไร” แม้จะรู้ตำแหน่งช่องโหว่และสิ่งที่แก้ไขแล้ว การทำซ้ำ exploit PoC ก็อาจต้องใช้ความพยายามไม่น้อย และตัวคลายการบีบอัดแบบ lossless ใน image decoder ก็อาจทนต่อ fuzzing ได้ค่อนข้างมาก สำหรับคนสายความปลอดภัยอาจเป็นเรื่องปกติ แต่ในฐานะคนนอกวงการ อ่านแล้วสนุกดี
มีคำถามอยู่สองสามข้อที่หาคำตอบชัดเจนไม่ได้ 1) เบราว์เซอร์ที่ใช้ Chrome เป็นฐาน ตัวอื่นอย่าง Brave ได้รับผลกระทบด้วยหรือไม่? 2) Chrome บนเดสก์ท็อปได้รับผลกระทบด้วยหรือเปล่า หรือเป็นปัญหาเฉพาะมือถือ? 3) ทำไมผมถึงไม่เคยได้ยินชื่อ WebP เลย? สงสัยว่าผมตัดขาดจากโลกไปเอง หรือมันเป็นเทคโนโลยีที่เน้นมือถือเป็นหลัก
Chrome บนเดสก์ท็อปก็ได้รับผลกระทบทั้งบน Linux และ Windows Chrome bundle libwebp ของตัวเอง ดังนั้นแม้ Linux distribution จะยังไม่ได้แพตช์ แต่ถ้า Chrome เป็นเวอร์ชันล่าสุด อย่างน้อยในแง่การโจมตีผ่านเบราว์เซอร์ก็ถือว่าโอเค
เบราว์เซอร์และระบบปฏิบัติการหลัก ๆ รองรับฟอร์แมตรูปภาพที่ไม่คุ้นชื่อจำนวนมากอย่างน่าประหลาดใจ เช่น บน MacOS สามารถโหลด KTX2(Khronos Texture Container) ได้ และบน Android สามารถโหลด DNG(Adobe Digital Negative) ได้ มี attack surface ที่น่าสนใจและเปิดเผยต่อผู้ใช้จำนวนมากให้ผู้โจมตีสำรวจไม่น้อย
บั๊กอยู่ในไลบรารี codec และ WebP เป็น ecosystem ที่ implementation แทบจะรวมศูนย์อยู่ตัวเดียว ทุกคนจึงใช้ไลบรารีเดียวกันและต้องแพตช์ทั้งหมด
Google ผลักดัน WebP เมื่อ 10 ปีก่อน แต่เพราะเป็นของ Chrome เท่านั้นอยู่นาน จึงไม่ได้แรงส่งมากนัก แม้ไม่ได้ถูกทำให้เป็นมาตรฐานอย่างถูกต้องนัก แต่ก็เป็นโอเพนซอร์ส รูปภาพคุณภาพต่ำบีบอัดได้ดีกว่า JPEG แต่ในรูปภาพคุณภาพสูงมักมีสีเลอะและดูเบลอ น่าขันที่ตอน WebP เริ่มได้รับการรองรับอย่างกว้างขวาง ก็เริ่มล้าสมัยทางเทคนิคไปแล้วเพราะ AVIF และ JPEG XL
หากอุปกรณ์ Android อยู่ในสถานะหมดการสนับสนุน เท่ากับว่าตอนนี้มันเสี่ยงต่อ 0-click exploit ที่กำลังถูกใช้จริงอยู่หรือเปล่า? หรือแค่อัปเดตแอป SMS, Chrome, WhatsApp, Signal ฯลฯ ก็เพียงพอที่จะปิดช่องทางอินพุตหลัก ๆ ได้แล้ว?
ถ้าอัปเดต Chrome บนอุปกรณ์ที่หมดการสนับสนุน ปัญหาใน Chrome ก็จะถูกแก้ แต่การแก้แอปอย่าง Signal หรือ WhatsApp จำเป็นต้องอัปเกรด Android OS Chrome bundle libwebp ของตัวเอง แต่แอปที่มีการเปิดรับสูงอย่างแอปแชตและ Gmail ใช้อินเทอร์เฟซที่ OS จัดให้เพื่อแสดงภาพ คาดว่าอุปกรณ์ Android ที่ยังอยู่ในช่วงสนับสนุนด้านความปลอดภัยจะเริ่มมีอัปเดตออกมาตั้งแต่ต้นเดือนตุลาคม
ประโยคที่ว่า “มีอินพุตจำนวนมากที่ทำให้ huffman_tables overflow ได้จริง” ดูเหมือนเป็นปัญหาที่ทั่วไปกว่านั้น เป็นโครงสร้างที่ซอฟต์แวร์ A สร้าง lookup table B แล้วตารางนั้นถูกใช้ประมวลผลสตรีมข้อมูลอินพุต
ต่อจากนี้ ถ้าเป็นนักพัฒนาที่ใส่ใจเรื่องความปลอดภัยหรือความถูกต้องแม้แต่นิดเดียว ก็ควรต้องรับประกันอย่างใดอย่างหนึ่ง: A) ซอฟต์แวร์ถูกเขียนมาให้ไม่มีข้อมูลอินพุตใดทำให้ lookup table ถูกใช้ผิดหรือทำงานล้มเหลวได้ หรือ B) ใช้เฉพาะในสภาพแวดล้อมที่ควบคุมได้ เช่น การสื่อสารแบบจุดต่อจุดที่ทั้งสองฝ่ายเชื่อถือได้ จึงรับประกันได้ว่าสตรีมจะไม่มีวันใช้ lookup table ผิดหรือทำให้เกิดความผิดปกติ
B แทบเป็นไปไม่ได้ยกเว้นในกลุ่มเล็ก ๆ หรือสำนักงาน และในระดับอินเทอร์เน็ตยิ่งเป็นไปไม่ได้จริง ๆ สุดท้ายจึงเหลือแค่ A แนวปฏิบัติที่ดีแบบทั่วไปของวิศวกรรมซอฟต์แวร์ในอนาคตคือ ถ้าใช้ lookup table ด้วยเหตุผลใดก็ตาม นักพัฒนาต้องรับประกันว่าตารางนั้นทำงานถูกต้องกับข้อมูลทุกประเภท หรือไม่ก็ต้องตรวจจับข้อมูลที่ผิดก่อนจะไปถึงตาราง และจัดการอย่างเหมาะสม
ถ้าเป็นนักวิจัยความปลอดภัยที่จริงจังและมีเวลา ผมคงรวบรวมรายการช่องโหว่ด้านความปลอดภัยทั้งหมดในอดีตที่เกี่ยวข้องกับ lookup table ไม่ทางใดก็ทางหนึ่ง แล้วอ่านทีละรายการเพื่อเทียบจุดร่วมกัน น่าจะมีแพตเทิร์นอยู่ จากนั้นค่อยไล่ดูซอฟต์แวร์ทั้งหมดที่ใช้ lookup table กับสตรีมข้อมูลและ audit หาช่องโหว่ แต่นี่ไม่ใช่งานที่คนคนเดียวทำได้ตลอดชีวิต เป็นกีฬาประเภททีมมากกว่า
การที่ การเปิดเผยซอร์สโค้ด ช่วยให้ NSO เจอบั๊กนี้มากน้อยแค่ไหนกันนะ? ถ้าโค้ดมีแต่ binary blob สงสัยว่า decompiler สมัยใหม่จะเพียงพอให้เข้าใจโค้ดและหาบั๊กที่เข้าใจยากแบบนี้ได้หรือไม่
น่าแปลกที่มันไม่ใช่ส่วน “ใหม่” ของฟอร์แมตภาพเลย Huffman compression มีมานานกว่า 70 ปีแล้ว canonical Huffman ก็เพียงแค่น้อยกว่านั้นไม่กี่สิบปี และแม้แต่ JPEG ก็ใช้ Huffman เป็นเทคโนโลยีเก่าแก่หลายสิบปี มีบทความอธิบายวิธี implement นับไม่ถ้วน ดูเหมือนควรเป็นเทคโนโลยีที่บั๊กใน implementation ต่าง ๆ ถูกสะสางไปแล้ว
เมื่อก่อนเคยอ่านสเปก JPEG และเคยเขียน decoder เลยลองดูสเปก WebP: https://developers.google.com/speed/webp/docs/webp_lossless_...
ส่วนสำคัญอยู่ในหัวข้อ 6 สิ่งแรกที่สะดุดตาคือวิธีประกอบโค้ดไม่ชัดเจน ต่างจากสเปก JPEG JPEG มี flowchart ที่อ่านเข้าใจง่ายจำนวนมากเกี่ยวกับกระบวนการ WebP ดูคล้าย LZH/deflate(zlib) และให้ความรู้สึกเหมือนชุดเศษ source code บางส่วนพร้อมคำอธิบายมากกว่า “สเปก”
หลังจาก GIF, JPEG, PNG ก็คิดอยากลองเขียน WebP decoder ดู แต่ดูแค่ “สเปก” ข้างต้นแล้วรู้สึกเหมือนมันแทบจะบอกว่าอย่าเขียนเลย
implementation ของ Huffman tree มี trade-off ที่แตกต่างกันมากมาย ดังนั้นแค่เป็นเทคโนโลยีเก่าก็ไม่ได้หมายความว่าบั๊กถูกสะสางหมดแล้ว Charles Bloom เคยบอกว่าแม้แต่งานวิจัยสำคัญเชิงตัดสินเรื่องการ optimize Huffman จากปี 1997 [1] ก็ยังไม่เป็นที่รู้จักมากนักจนถึงปี 2010 และ optimization จำนวนมากถูกค้นพบซ้ำแล้วก็ถูกลืมไป ดังนั้นจึงมีความเป็นไปได้สูงว่าจะมี implementation ที่ไม่มีประสิทธิภาพอยู่มาก
[1] https://cbloomrants.blogspot.com/2010/08/08-12-10-lost-huffm...
เดี๋ยวนี้ดูเหมือนแม้แต่การดูภาพก็ทำไม่ได้โดยไม่ต้องกังวลเรื่องความปลอดภัย
ฟังดูเหมือนความเจ็บปวดในการเติบโตแบบคลาสสิกจากการใช้ C ซึ่งเป็นภาษาที่ไม่ปลอดภัย ผมเข้าใจว่ามันน่าดึงดูดเพราะความเร็วของเบราว์เซอร์ แต่ก็อยากให้อุตสาหกรรมเลิกแนวทางที่คอยส่งเสริมให้ทำผิดซ้ำแบบเดิม ๆ มาตั้งแต่เริ่มใช้ C
ให้ความรู้สึกเหมือนสร้างสะพานด้วย สกรูปลายสว่าน แทนหมุดย้ำเพราะมันเร็วกว่า พอสะพานเริ่มแอ่นก็แค่ขันสกรูเพิ่มเข้าไป
“ข่าวดีก็คือ Apple และ Chrome ตอบสนองได้ยอดเยี่ยมสมกับความเร่งด่วนของปัญหานี้” แบบนี้ยอมรับได้ยากนะ คนที่จัดปัญหานี้เป็นของ Chrome เท่านั้น คือ Google เอง แค่ดู 7 วันที่ผ่านมาก็เห็นแล้วว่า Linux distribution รายใหญ่ทั้งหมดต้องเร่งปล่อยอัปเดต และ Red Hat ให้คะแนน 9.6 ด้วย Python Docker image ที่ถูก pull ไปมากกว่า 1 พันล้านครั้ง, Puppeteer, WordPress, Node.js ฯลฯ ก็ได้รับผลกระทบ แต่ CRBug ก็ยังเป็น private อยู่
เว็บไซต์อย่าง BleepingComputer ก็รายงานไปตามที่เห็นโดยไม่ได้ตรวจสอบ และบริษัทรักษาความปลอดภัยจำนวนมากที่ปฏิบัติต่อ issue นี้เหมือนเป็นบุคคลที่สามก็เหมือนกัน ถ้ารู้ว่าอีกฝ่ายไม่ได้ทำ due diligence ก็สร้างความเชื่อใจกันได้ยากจริง ๆ
Adam Caudill เขียนบทความดี ๆ ชื่อ “Whose CVE is it anyway?”[0] พร้อมยกกรณีที่ 1Password แพตช์ตั้งแต่ช่วงแรก และชี้ประเด็นที่พูดถึงตรงนี้ได้ดี Citizen Lab ปฏิเสธที่จะตอบว่าสอง issue นี้เกี่ยวข้องกันหรือไม่ แต่มีบางอย่างที่ไม่ต้องเป็นอัจฉริยะก็พอมองออก
[0]: https://adamcaudill.com/2023/09/14/whose-cve-is-it-anyway/
ผู้เขียนก็พูดว่าระบบอื่น ๆ อีกมากต้องแพตช์เช่นกัน เพียงแต่ว่าใน Python Docker image ที่ถูก pull ไป 1 พันล้านครั้งนั้น มีสักกี่ตัวที่เรนเดอร์ภาพ WebP ที่ไม่น่าเชื่อถือ? Node และอื่น ๆ ก็เช่นกัน แน่นอนว่าต้องแพตช์อย่างรวดเร็ว แต่ไม่ใช่ระดับเดียวกับ iOS/Android/Chrome
ผู้คนนับล้านทั่วโลกได้รับผลกระทบจากไลบรารีนี้ และผลกระทบก็ทวีคูณไปตามอุปกรณ์และแอปที่แต่ละคนใช้
ผมชอบ C นะ แต่คิดว่าไลบรารีที่ผู้คนนับล้านทั่วโลกใช้ ไม่ควรใช้ C สัดส่วนความเสี่ยงในไลบรารีแกนหลักแบบนี้สูงเกินไป ต่อให้เป็นผู้เชี่ยวชาญ C สักวันก็ต้องพลาด
นี่น่าจะเป็นการแก้ไข https://github.com/webmproject/libwebp/commit/dce8397fec159c...
“malloc fail” นี่ชวนหงุดหงิด Slack, Discord, Teams ไปจนถึง OS สมัยใหม่ทั้งหมดล้วนได้รับผลกระทบ
C/C++ และภาษาไดนามิกทำให้พื้นผิวของ undefined behavior และบั๊กละเอียดอ่อนขยายใหญ่ขึ้น และแม้แต่นักพัฒนาที่ฉลาดที่สุดก็ยัง lint ได้ยากและเป็นภาระ ไลบรารีพื้นฐานควรถูกตรวจสอบความถูกต้องเชิงรูปแบบในลักษณะคล้ายกับ seL4
อีกปัญหาหนึ่งคือความไม่เป็นมืออาชีพที่แพร่ไปทั่ว FOSS รวมถึงการไม่ให้ความสำคัญกับความเข้มงวด คุณภาพ ความถูกต้อง และความปลอดภัย วิธีสร้างจักรวรรดิบนผืนทรายอย่างทุกวันนี้เป็นเรื่องโง่เขลา