- ทีม Crusaders of Rust ค้นพบบั๊ก use-after-free ในตัวจัดตารางแพ็กเก็ตของ Linux และพัฒนาเอ็กซ์พลอยต์ขึ้นมา
- ในการแข่งขัน Google kernelCTF ทีมพยายามทำการปรับแต่งประสิทธิภาพระดับสูงเนื่องจาก จำเป็นต้องมีวิธีแก้ PoW (Proof of Work) ที่รวดเร็ว
- ด้วย แอสเซมบลีที่เขียนเองและการปรับแต่ง SIMD โดยใช้คำสั่ง AVX512IFMA ทีมทำความเร็วได้เกือบ 7 เท่าเมื่อเทียบกับอิมพลีเมนเทชัน Python/GMP และ Rust เดิม
- มีการจูนอย่างละเอียดตั้งแต่ หลักการทำงาน การคำนวณแบบโมดูลาร์ การจัดการหน่วยความจำ และการใช้รีจิสเตอร์ จนลดเวลาในการประมวลผล PoW ลงเหลือ 0.21 วินาที
- สุดท้ายทีมส่งผลงานเข้า kernelCTF สำเร็จด้วย เวลาสั้นที่สุดเป็นประวัติการณ์ (3.6 วินาที) หลังจากนั้นนโยบาย PoW ก็ถูกยกเลิกอย่างเป็นทางการ
ภาพรวมและจุดมุ่งหมาย
- ในเดือนพฤษภาคม 2025 William Liu และ Savy Dicanosa จากทีม Crusaders of Rust พบช่องโหว่ use-after-free ใน Linux และเข้าร่วมการแข่งขัน kernelCTF ของ Google
- บทความนี้กล่าวถึง กระบวนการปรับแต่ง เพื่อแก้การตรวจสอบ PoW (Proof of Work) ให้เร็วขึ้น และส่งผลงานให้ไวกว่า ทีมความปลอดภัยระดับโลก อื่น ๆ ในการแข่งขันชิงบั๊กบาวน์ตีที่มีเวลาจำกัด
ขั้นตอนการส่ง kernelCTF และฉากหลังของการแข่งขัน
- kernelCTF เป็นการแข่งขันที่มี เงินรางวัลก้อนใหญ่ ทำให้ ทีมความปลอดภัยมืออาชีพ จากทั่วโลกเข้าร่วมอย่างจริงจัง ทั้งด้านระบบส่งอัตโนมัติและการปรับแต่ง PoW
- ในแต่ละรอบการส่ง (เปิดทุก 2 สัปดาห์) จะมี เพียงทีมที่เร็วที่สุดทีมเดียวเท่านั้นที่ได้รับรางวัล
- ขั้นตอนการส่งมีดังนี้:
- เชื่อมต่อเข้าเซิร์ฟเวอร์ตามเวลาที่กำหนด
- แก้ PoW ซึ่งใช้เวลาหลายวินาที
- รอ VM บูต
- รันโค้ดเอ็กซ์พลอยต์และดึง flag
- ส่ง Google Form
- ช่วงหลังมีสถิติส่ง flag สำเร็จใน 4.5 วินาที แต่แค่ PoW กับการบูต VM ก็ใช้เวลา 6.5 วินาทีแล้ว จึงจำเป็นต้องเร่งความเร็วการแก้ PoW
การวิเคราะห์อัลกอริทึม PoW (VDF-Sloth) และการปรับแต่งระยะแรก
- PoW ของ kernelCTF ใช้ verifiable delay function แบบคำนวณเชิงลำดับชื่อ sloth VDF
- สำหรับจำนวนเต็มขนาด 1280 บิต
x จะทำการคำนวณ ยกกำลังสองแบบโมดูลาร์และกลับบิต ซ้ำ ๆ
- แม้อิมพลีเมนเทชันเดิม (Python+gmpy และ Rust) จะไม่สามารถได้ประโยชน์จากการขนานหลายคอร์ และ GMP ก็ถูกปรับแต่งมาดีพอสมควรอยู่แล้ว
- อย่างไรก็ตาม ทีมใช้ข้อเท็จจริงที่ว่าการคำนวณโมดูลาร์อิงกับจำนวนเมอร์แซนน์
2^1279-1 เพื่อสร้างอิมพลีเมนเทชันโมดูลาร์แบบแมนนวลใน C++ ที่เร็วกว่าเดิม และเพิ่มประสิทธิภาพได้จนเหลือ 1.9 ถึง 1.4 วินาที
การเปลี่ยนผ่านครั้งใหญ่สู่ AVX512IFMA และอิมพลีเมนเทชัน SIMD ความเร็วสูงมาก
- หลังจากนั้นทีมมุ่งไปที่ ISA แบบ AVX512 และโดยเฉพาะ AVX512IFMA ซึ่งมีคำสั่ง คูณและสะสมแบบ 52 บิต
- ทีมแบ่งจำนวน 1280 บิตออกเป็น limb ขนาด 52 บิต เพื่อเร่งความเร็วด้วย SIMD ให้สูงสุด (25 limb → ใช้ zmm รีจิสเตอร์ 4 ตัว)
- มีการปรับจูนระดับล่างซ้ำแล้วซ้ำอีก ทั้งเรื่องสมมาตรของการคำนวณ modular square, accumulation mask, memory broadcast, การจัดสรรรีจิสเตอร์ และการเปรียบเทียบแบบไร้ branch
- ใช้ ASM (inline assembly) เพื่อป้องกันปัญหา register spill/reload ที่ไม่มีประสิทธิภาพจากคอมไพเลอร์ และด้วยการปรับแต่ง broadcast กับ masking จึงดันความเร็วสุดท้ายลงมาได้ถึง 0.21 วินาที
การทำระบบส่ง PoW อัตโนมัติและสถานการณ์จริงในการแข่งขัน
- ในการส่งจริง ทีมใช้ เซิร์ฟเวอร์ Google Cloud แบบ Zen 5 (ภูมิภาค Amsterdam) เพื่อลด latency ของเครือข่ายไปยัง Google Form
- ด้วยโปรแกรมส่งอัตโนมัติ (แพตช์คำขอ POST ของ Google Form และปรับแต่งร่วมกันภายในทีม) ทีมจึงส่ง flag สำเร็จใน 3.6 วินาที ซึ่งเป็นสถิติสั้นที่สุดเท่าที่เคยมีมา
- ต่อมา ผู้ดูแล kernelCTF ประกาศ ยกเลิกนโยบาย PoW อย่างเป็นทางการ ทำให้หลุดพ้นจากการแข่งขันด้านการปรับแต่ง PoW และสามารถเปิดเผยเทคนิคได้
รายละเอียดการอิมพลีเมนต์ขั้นสูง
การปรับแต่งการคำนวณแบบโมดูลาร์
- การคำนวณโมดูโล
2^1279-1 (จำนวนเฉพาะ) ถูกแทนที่ด้วยการเลื่อนบิตและการคำนวณเลขคณิตพื้นฐานไม่กี่ครั้ง ทำให้ได้การคำนวณโมดูลาร์ที่เร็วกว่า GMP มาตรฐานมาก
Big-int squaring บน AVX512IFMA
- ใช้คำสั่งคูณและสะสมแบบ 52 บิตของ AVX512 (
vpmadd52luq, vpmadd52huq) เพื่อคูณและสะสม limb แบบขนานทีละ 8 ตัว
- เนื่องจากโครงสร้างมี 25 limb จึงกระจายไปบน zmm 4 ตัว และออกแบบตรรกะให้ลดการ masking/accumulation ที่ไม่จำเป็นให้เหลือน้อยที่สุด
การจัดวางข้อมูลและการใช้รีจิสเตอร์
- ใช้การจัดวางข้อมูลแบบเป็นชั้นตามออฟเซ็ต การย้ายข้อมูลระหว่างรีจิสเตอร์ (
valignq, broadcast) และเทคนิคอื่น ๆ เพื่อลดคอขวดของ SIMD
- เพิ่มจำนวน accumulator เป็น 2 เท่าเพื่อให้ได้ throughput สูงสุดโดยไม่ต้องรอหน่วยคูณ
- ทำ carry propagation เท่าที่จำเป็นขั้นต่ำเท่านั้น
ระบบส่งอัตโนมัติขั้นสุดท้ายและการทำงานร่วมกัน
- มีการจัดวางสมาชิกทีมเพื่อโจมตีในช่วงเวลากลางดึก พร้อมปรับแต่งตำแหน่งเครือข่ายและการรัน exploit
- ในการส่งจริง ทุกอย่างถูกทำอัตโนมัติอย่างต่อเนื่อง ตั้งแต่แก้ PoW, รันเอ็กซ์พลอยต์, ใส่ flag ไปจนถึงส่งคำขอ POST ไปยัง Google Form
บทสรุปและความหมาย
- การปรับแต่ง PoW ของ kernelCTF เป็นงานที่ต้องอาศัยความเข้าใจฮาร์ดแวร์อย่างลึกซึ้งระดับผ่าตั้งแต่บิต หน่วยความจำ รีจิสเตอร์ และ CNN
- เมื่อไม่มีนโยบาย PoW แล้ว จุดแข่งขันก็จะเหลือเพียง ความเร็วของเครือข่ายและเอ็กซ์พลอยต์ล้วน ๆ
- กรณีนี้แสดงให้เห็นถึง การบรรจบกันของการแฮ็กในโลกจริงกับการประมวลผลสมรรถนะสูง และองค์ความรู้ด้านการปรับแต่งอัลกอริทึมพร้อมโค้ดโอเพนซอร์สก็น่าจะยังมีประโยชน์ต่อชุมชนนักวิจัยต่อไป
หมายเหตุและภาคผนวก
- มีการเปิดเผยโค้ดทั้งหมดของอัลกอริทึม PoW และฟังก์ชันแปลงข้อมูล (GMP <-> อาร์เรย์ 52 บิต), การคำนวณโมดูลาร์บน SIMD และโค้ด ASM ที่ใช้จูนประสิทธิภาพ
- แม้จะเป็นโค้ดแบบ “ลุยจริง” ที่พัฒนาอย่างเข้มข้นภายในเวลาประมาณ 12 ชั่วโมงและนำไปใช้ภาคสนามทันที แต่ก็เปิดซอร์สภายใต้สัญญาอนุญาต GNU AGPL 3.0
- หากมีคำถามหรืออยากร่วมมือด้าน VDF สามารถติดต่อได้ทาง Discord(@forevermilk)
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ทีมที่ชนะทำเวลาได้ 3.6 วินาที และอันดับ 2 ทำได้ 3.73 หรือ 3.74 วินาที จึงทำให้นึกว่าอันดับ 2 ก็น่าจะปรับแต่ง PoW หรืออาจใช้ FPGA ด้วยเช่นกัน เมื่อเทียบกับการส่งงานด้วย FPGA ก่อนหน้านี้ที่ใช้เวลาเกิน 4 วินาที ก็น่าเสียดายที่ผู้เขียนไม่ได้พูดถึงว่าผลงานอันดับ 2 ในสัปดาห์นี้อาจเป็นสถิติระดับประวัติการณ์เหมือนกัน
วิธีนี้ให้ความรู้สึกว่าคล้ายมากกับแนวทางที่ใช้ใน implementation ของ RSA ที่ปรับแต่งสำหรับ AVX-512 เพราะ RSA ก็ต้องคำนวณการยกกำลังขนาดใหญ่มากเช่นกัน งานวิจัยนี้(https://dpitt.me/files/sime.pdf)อธิบายเทคนิค windowing และการปรับขนาดหน้าต่างแบบยืดหยุ่นได้ ส่วน implementation ของ RSA บน AVX-512 จะเพิ่มการเก็บผลคูณไว้ในตารางช่วง [0..2^{window-size}) เพื่อเรียกใช้ผลในแต่ละหน้าต่าง ดูตัวอย่างจริงได้ใน rsaz-2k-avx512.pl ของ aws-lc
สำหรับข้ออ้างที่ว่า AVX512 รองรับบน CPU ฝั่งผู้บริโภคมาหลายเจเนอเรชัน จำได้ว่าก่อน Rocket Lake (รุ่น 11) นั้น AVX512 มีให้ใช้เฉพาะในรุ่น enthusiast, Xeon และโปรเซสเซอร์มือถือบางตัวเท่านั้น หลังรุ่น 12 ที่เริ่มใช้ P/E core มันก็ถูกปิดการใช้งานและหายไปภายในไม่กี่เดือน มีการคาดการณ์ว่าถ้า AMD ประสบความสำเร็จกับ AVX512, Intel ก็จะนำกลับมาอีกครั้ง ส่วนตัวใช้งาน i9-11900 อยู่
มีความสงสัยต่อธรรมชาติของการแข่งขัน CTF โดยมองว่าควรใช้วิธีแบ่งเงินรางวัลให้ทุกทีมที่ส่ง flag ได้ภายในช่วงเวลาที่กำหนด แทนการแข่งขันด้านความเร็วในการส่ง
ถ้าเข้าใจไม่ผิด นี่คือ proof of work 4 วินาทีและมีโครงสร้างการจ่ายเงินเดือนละครั้ง จึงสงสัยว่าในแต่ละเดือนมี exploit จำนวนมากและมีการแข่งขันดุเดือดขนาดนั้นเลยหรือไม่
เป็นความท้าทายที่น่าทึ่ง แต่ก็ให้ความรู้สึกว่าความซับซ้อนและความชวนขำของอุปสรรคเพื่อจะชนะมันสูงมาก เหมือนเครื่องจักรแบบ Rube Goldberg
ถ้าอยากรู้เพิ่มเติมเกี่ยวกับส่วน base-52 ที่กล่าวถึงในบทความ แนะนำให้อ่านโพสต์นี้ที่กำลังเป็นประเด็นวันนี้(https://news.ycombinator.com/item?id=44132673)
คณิตศาสตร์มันเท่มาก
มีการแนะนำ sloth ซึ่งเป็น VDF (Verifiable Delay Function) ที่ใช้ใน proof of work โดยต้องอาศัยการคำนวณยาวต่อเนื่องเพื่อพิสูจน์การผ่านของเวลา แต่ผลลัพธ์สามารถตรวจสอบได้อย่างรวดเร็ว การคำนวณมีลักษณะเป็นลำดับต่อกัน จึงไม่สามารถลด runtime ได้แม้ใช้หลายคอร์ จึงมีคำถามว่าสิ่งนี้อาจกลายเป็นตลาดใหม่ให้ผู้ผลิต CPU ได้หรือไม่ พร้อมเสนอแนวคิดเรื่องคำสั่งเฉพาะสำหรับการวน sloth และผลลัพธ์ของมัน รวมถึงฟังก์ชันป้องกันการโอเวอร์คล็อกระดับฮาร์ดแวร์ อีกไอเดียหนึ่งคือให้ CPU ตรวจสอบ uptime ของตัวเองแล้วลงลายเซ็นพร้อม challenge ซึ่งคล้ายแนวคิด proof of stake ที่ยังคงใช้ CPU ทำงานจริงไปพร้อมกับพิสูจน์การครอบครอง CPU เป็นเวลา n วินาที
สงสัยว่าฟังก์ชัน Python ในบล็อกเทียบเท่ากับ implementation ของ Google PoW อย่างไร เพราะตามได้ค่อนข้างยาก
exponent = (p + 1) // 4มีค่าเป็น 2^1277 ดังนั้นการยกตัวเลขขึ้นด้วยเลขชี้กำลังมหึมาขนาดนั้นต้องมีการยกกำลังสอง 1277 ครั้ง และฟังก์ชัน Python ก็ทำสิ่งนี้จริง ๆ ถ้าค่าเริ่มต้นคือ x แต่ละครั้งที่ยกกำลังสองก็จะคูณเลขชี้กำลังเป็น 2 เท่าไปเรื่อย ๆ จนสุดท้ายกลายเป็น 2^1277 และนี่คือหลักการของมัน