การวิเคราะห์ทางเทคนิคการแฮก Wormhole Bridge: การถูกโจมตีมูลค่า 326 ล้านดอลลาร์
เมื่อวันที่ 2 กุมภาพันธ์ 2022 สะพานโทเคน Wormhole สูญเสีย wETH จำนวน 120,000 เหรียญ — ประมาณ 326 ล้านดอลลาร์ในขณะนั้น — ซึ่งถือเป็นหนึ่งในการแฮกสมาร์ตคอนแทรกต์ครั้งใหญ่ที่สุดในประวัติศาสตร์ DeFi การโจมตีครั้งนี้ไม่ต้องการใช้กุญแจที่ถูกขโมย, การหลอกลวงทางสังคม หรือการควบคุมเครือข่าย Guardian validator ในสัดส่วนส่วนใหญ่ แต่ต้องการสิ่งเดียว: API โปรแกรม Solana ที่เลิกใช้ซึ่งล้มเหลวในการตรวจสอบว่ามันกำลังอ่านข้อมูลจากบัญชีใด
ความเข้าใจการโจมตีนี้เป็นสิ่งสำคัญสำหรับทุกทีมที่พัฒนาบน Solana, โปรโตคอลที่อาศัยการส่งข้อความข้ามเครือข่าย และผู้ตรวจสอบที่ทบทวนโปรแกรม Solana สาเหตุหลักคือช่องโหว่ในการตรวจสอบสมาร์ตคอนแทรกต์ในโปรแกรมสะพาน Wormhole บน Solana — ไม่ใช่การถูกแฮกกุญแจ หรือการล้มเหลวของเครือข่าย Guardian กุญแจ Guardian ไม่ถูกแตะต้องเลย รหัสของสะพานเองเป็นฝ่ายมอบสิทธิ์ให้กับผู้โจมตีโดยที่ไม่ควรให้
ช่องโหว่ทางเทคนิคหลักในการแฮก Wormhole คืออะไร?
ช่องโหว่อยู่ในคำสั่ง verify_signatures ของโปรแกรมสะพาน Wormhole บน Solana (bridge.so) ฟังก์ชันนี้มีหน้าที่ตรวจสอบว่า บัญชี SignatureSet — ซึ่งประกอบด้วยลายเซ็น Ed25519 หรือ Secp256k1 จากโหนด Guardian — เป็นฉันทามติที่แท้จริงก่อนอนุญาตให้ดำเนินการ Verifiable Action Approval (VAA)
จุดบกพร่องคือ: verify_signatures ใช้ฟังก์ชัน solana_program::sysvar::instructions::load_instruction_at แบบที่เลิกใช้แล้วเพื่อตรวจสอบว่ามีคำสั่ง Secp256k1 pre-verification ถูกเรียกก่อนในธุรกรรมเดียวกัน ฟังก์ชันที่เลิกใช้นี้จะไม่ตรวจสอบว่า บัญชีที่ถูกส่งผ่านมาเป็น Solana instructions sysvar (Sysvar1nstructions1111111111111111111111111) จริงหรือไม่ มันอ่านจากบัญชีใดๆ ที่อยู่ ณ ตำแหน่งนั้น — รวมถึงบัญชีที่ถูกควบคุมโดยผู้เรียกเอง
ดังนั้น ผู้โจมตีจึงสามารถส่งบัญชีปลอมที่เลียนแบบรูปแบบของ instructions sysvar และมีข้อมูลลายเซ็นที่ผู้โจมตีควบคุมไว้ล่วงหน้าพร้อมกับ payload ที่เลือกได้ ฟังก์ชันจะอ่านข้อมูลปลอมนี้ ค้นพบคำสั่ง Secp256k1 “ปรากฏอยู่” (ในบริบทที่ต่างออกไปโดยสิ้นเชิง) ทำเครื่องหมาย VAA ว่าได้รับอนุมัติจาก Guardian และคืนค่าความสำเร็จกลับมา
เมื่อได้ VAA ที่ได้รับอนุมัติด้วยการปลอม ผู้โจมตีได้เรียกใช้งาน complete_wrapped ซึ่งเชื่อถือการอนุมัติ VAA จากโปรแกรมสะพานเพื่อตรวจสอบการอนุญาตในการสร้างโทเคนห่อหุ้มบน Solana ผลลัพธ์คือ: มีการสร้าง wETH จำนวน 120,000 ตัวโดยไม่มี ETH ที่ถูกล็อกไว้บน Ethereum แต่อย่างใด
การแก้ไข — การแทนที่ load_instruction_at ด้วย load_instruction_at_checked ซึ่งบังคับให้ตรวจสอบว่าบัญชีที่อ่านจริงๆ คือ instructions sysvar — ได้ถูกคอมมิทไว้ในคลังข้อมูล GitHub ของ Wormhole ก่อนเกิดการโจมตีแต่ยังไม่ถูกดีพลอยลง mainnet
| ปัจจัย | คำอธิบาย | ผลกระทบ |
|---|---|---|
Deprecated sysvar API |
load_instruction_at แบบไม่มีตัวเลือก _checked; ไม่มีการตรวจสอบเจ้าของบัญชีที่ส่งมาในตำแหน่งที่ระบุ |
ผู้โจมตีสามารถส่งบัญชีคำสั่งปลอมแทน instructions sysvar ตัวจริงได้ |
verify_signatures bypass |
ฟังก์ชันยอมรับบัญชี SignatureSet ที่ผู้โจมตีปลอมแปลงเป็นหลักฐานฉันทามติ Guardian โดยไม่ตรวจสอบแหล่งที่มาของบัญชี |
มอบสิทธิ์ในการสร้างโทเคนโดยไม่มีลายเซ็น Guardian ที่แท้จริง |
Missing account owner check |
ไม่มีการตรวจสอบว่า บัญชี SignatureSet เป็นของโปรแกรม instructions sysvar (Sysvar1nstructions11...) |
การละเว้นการตรวจสอบนี้คือรากฐานของช่องโหว่ทั้งหมด |
Wrapped asset minting authority |
โปรแกรมสะพาน Solana มีสิทธิ์สร้างโทเคนห่อหุ้มโดยไม่มีข้อจำกัด; สิทธิ์การอนุญาตต้องมีแค่ VAA ที่ถูกทำเครื่องหมายว่าอนุมัติ | สร้าง wETH จำนวน 120,000 ตัวบน Solana โดยไม่มี ETH ถูกล็อกใน Ethereum; มูลค่าประมาณ 326 ล้านดอลลาร์ในช่วงการโจมตี |
การโจมตี Wormhole แตกต่างจากการโจมตีสะพานอื่นๆ เช่น Ronin อย่างไร?
การแฮกสะพาน Ronin (มีนาคม 2022, ประมาณ 625 ล้านดอลลาร์) มักถูกเปรียบเทียบกับ Wormhole ในการอภิปรายเกี่ยวกับความล้มเหลวของความปลอดภัยสะพาน แต่พวกเขาเป็นความล้มเหลวในรูปแบบที่แตกต่างกันโดยสิ้นเชิง
Wormhole คือ บั๊กข้อผิดพลาดในการตรวจสอบสมาร์ตคอนแทรกต์ ในโปรแกรมสะพานบน Solana เครือข่าย Guardian — ที่เป็นโครงสร้างลายเซ็นแบบ threshold ของ 19 โหนด — ไม่ได้รับผลกระทบ ผู้โจมตีหลบเลี่ยงเครือข่ายโดยใช้ช่องโหว่ที่ฟังก์ชัน verify_signatures ไม่เคยตรวจสอบ ว่ากำลังอ่านจากบัญชีใด กุญแจ Guardian ยังสมบูรณ์ เครือข่ายยังดำเนินการอยู่ และทั้งหมดนี้ไม่มีความสำคัญ เพราะโค้ดไม่เคยขอคำยืนยันจาก Guardian จริงๆ
Ronin คือ การขโมยกุญแจแบบปฏิบัติการ Sky Mavis เป็นผู้ดำเนินโหนด validator 5 ใน 9 ตัวของ Ronin ในเดือนพฤศจิกายน 2021 Axie DAO ได้มอบหมายสิทธิ์การลงลายเซ็นชั่วคราวให้ Sky Mavis เพื่อจัดการปริมาณธุรกรรม สิทธิ์นี้ไม่ถูกเพิกถอนเมื่อหมดอายุ ผู้โจมตี — ซึ่งถูกระบุว่าเป็นกลุ่ม Lazarus — เจาะเข้าระบบภายในของ Sky Mavis และได้กุญแจ validator 4 ตัว ใช้สิทธิ์ที่ยังไม่หมดอายุในการลงลายเซ็น Axie DAO ได้รับลายเซ็นที่ 5 ผ่านโหนด RPC gas-free ของ Sky Mavis ด้วยลายเซ็นดั้งเดิมครบ 5 ใน 9 พวกเขาส่งคำขอถอนเงินที่ถูกต้องตามกฎหมายถึงสมาร์ตคอนแทรกต์สะพาน Ronin ไม่มีการใช้บั๊กสมาร์ตคอนแทรกต์สะพานเลย สะพานทำงานตามที่ถูกออกแบบเมื่อได้รับลายเซ็น validator ที่ถูกต้องครบถ้วน
| Wormhole (ก.พ. 2022) | Ronin (มี.ค. 2022) | |
|---|---|---|
| ช่องทางโจมตี | ข้ามการตรวจสอบบัญชีโปรแกรม Solana | การหลอกลวงทางสังคมและการขโมยข้อมูลรับรองของโหนด Sky Mavis |
| วิธีการโจมตี | บัญชี SignatureSet ปลอมผ่าน API sysvar ที่เลิกใช้ |
การถอนเงินที่ลงลายเซ็นจริงจากกุญแจ validator ที่ถูกขโมย |
| เครือข่าย Guardian / validator | สมบูรณ์; โค้ดข้ามระบบ ไม่ใช่แฮกเกอร์ | ถูกเจาะ — ผู้โจมตีได้กุญแจ validator 5 ใน 9 ตัว |
| วิธีการส่งผลกระทบ | การสร้างโทเคนโดยไม่ได้รับอนุญาตบน Solana โดยไม่มี ETH ถูกล็อกบน Ethereum | ถอนเงินโดยตรงจากสมาร์ตคอนแทรกต์สะพาน Ronin ผ่านลายเซ็นที่ถูกต้อง |
| จำนวนที่ถูกขโมย | ประมาณ 326 ล้านดอลลาร์ (120,000 wETH) | ประมาณ 625 ล้านดอลลาร์ (173,600 ETH + 25.5 ล้าน USDC) |
| ข้อสรุปด้านความปลอดภัย | การตรวจสอบเจ้าของบัญชีเป็นข้อบังคับในโปรแกรม Solana; ลายเซ็น threshold ใช้ได้ก็ต่อเมื่อสะพานอ่านมันจริง | ระบบลายเซ็น threshold ป้องกันไม่ได้ถ้ากุญแจส่วนใหญ่ถูกขโมย; ต้องบังคับเพิกถอนสิทธิ์ในกรณีมอบหมาย |
ขั้นตอนของการโจมตี Wormhole
-
ปลอมแปลงบัญชี. ผู้โจมตีสร้างบัญชี Solana ที่เลียนแบบรูปแบบที่คาดหวังในตำแหน่ง
SignatureSetในข้อมูลคำสั่งของโปรแกรมสะพาน Wormhole บัญชีนี้มีลายเซ็นที่ผู้โจมตีควบคุม — เป็นลายเซ็น Ed25519/Secp256k1 ที่ถูกต้อง แต่แมชกับ payload ของ VAA ที่ผู้โจมตีออกแบบเพื่ออนุญาตให้สร้าง wETH 120,000 ตัว ไปยังที่อยู่ Solana ของผู้โจมตี -
ข้ามผ่าน API sysvar ที่เลิกใช้. ผู้โจมตีส่งธุรกรรมที่เรียก
verify_signaturesในโปรแกรมสะพาน Solana ของ Wormhole โปรแกรมเรียกใช้load_instruction_at— ตัวแปรที่เลิกใช้และไม่ตรวจสอบ — เพื่อตรวจสอบว่าคำสั่ง Secp256k1 ถูกเรียกก่อนหน้านี้ในธุรกรรมเดียวกันหรือไม่load_instruction_atอ่านข้อมูลจากบัญชีใดก็ได้ ณ ตำแหน่งที่กำหนดโดยไม่ตรวจสอบว่าเป็น instructions sysvar ตัวจริงหรือไม่ -
หลักฐานปลอมถูกยอมรับ. ฟังก์ชัน
verify_signaturesตรวจสอบลายเซ็นในบัญชีที่ผู้โจมตีสร้างขึ้น พบว่าถูกต้องตามหลักคริปโตกราฟี (ผู้โจมตีเซ็นเองกับ payload ของตนเอง) และทำเครื่องหมาย VAA ว่าได้รับอนุมัติจาก Guardian โดยที่ไม่ได้สอบถามเครือข่าย Guardian จริงๆ -
อนุญาตให้สร้างโทเคน. ผู้โจมตีเรียกใช้งาน
complete_wrappedพร้อมกับ VAA ที่ได้รับอนุมัติแล้ว โปรแกรมสะพานเชื่อถือสถานะอนุมัติของ VAA จึงสร้าง wETH จำนวน 120,000 ตัวใน Solana ให้กับที่อยู่ของผู้โจมตี -
ดึงสินทรัพย์ข้ามเครือข่าย. ผู้โจมตีส่ง wETH ที่สร้างขึ้นกลับไปยัง Ethereum ผ่านช่องทาง cross-chain ที่ถูกต้องของ Wormhole — เพราะ wETH อยู่ในกระเป๋าของผู้โจมตีบน Solana สะพานจึงประมวลผลการถอนเหมือนการโอนปกติ มูลค่า 326 ล้านดอลลาร์ของ wETH ที่ไม่มีหลักประกันถูกโยกย้ายไปยัง Ethereum จากนั้นผู้โจมตีแปลงเป็น ETH และ stablecoin แล้วถอนออก Jump Crypto บริษัทแม่ของ Wormhole ได้เติม ETH จำนวน 120,000 ตัวที่ถูกขโมยคืนจากสำรองของตนเองเพื่อชดเชยให้ผู้ใช้สะพาน
บทเรียนทางเทคนิคที่สำคัญที่สุดสำหรับโปรแกรม Solana และสะพานข้ามเครือข่าย
1. ทุก AccountInfo ที่ส่งไปยังโปรแกรม Solana เป็นข้อมูลที่ผู้โจมตีควบคุมได้จนกว่าจะพิสูจน์ได้ว่าไม่ใช่
นี่คือกฎพื้นฐานของความปลอดภัยโปรแกรม Solana โปรแกรมต้องตรวจสอบ owner, key และ — ถ้าใช้ — ฟิลด์ executable และ is_signer ของบัญชีทุกบัญชีที่ได้รับ ฟังก์ชัน load_instruction_at ที่เลิกใช้รับบัญชีใดๆ ที่วางไว้ ณ ตำแหน่งที่ระบุ ตัวแทนปัจจุบันคือ load_instruction_at_checked ที่บังคับตรวจสอบว่าบัญชีนั้นเป็น instructions sysvar จริงก่อนอ่าน ข้อปฏิบัตินี้ถูกประเมินว่าเป็นความบกพร่องร้ายแรงในมาตรฐานการตรวจสอบ Solana ของ Soken
2. แยกสิทธิเฉพาะระหว่างการตรวจสอบลายเซ็นกับการสร้างโทเคน
สิทธิ์ในการสร้างโทเคนสะพานต้องอยู่หลังโมดูลตรวจสอบที่ขอหลักฐานซ้ำจากสถานะที่เป็นทางการและโปรแกรมเป็นเจ้าของ — ไม่ใช่จากบัญชีที่ผู้เรียกส่งมา เมื่อ verify_signatures ยอมรับบัญชีที่ผู้โจมตีควบคุมเป็นแหล่งที่มา ความแตกต่างระหว่าง “เครือข่ายอนุมัติหรือไม่?” กับ “เราสร้างโทเคนได้ไหม?” ก็พังทลายไปโดยสิ้นเชิง คำสั่งสร้างโทเคนควรใช้อนุญาตจากสถานะที่โปรแกรมเขียนหลังตรวจสอบข้อมูล Guardian จริงแล้ว
3. ต้องบังคับใช้การป้องกันการเล่นซ้ำ VAA ในบล็อกเชน
แม้ SignatureSet จะเป็นของแท้ก็ควรให้ complete_wrapped ปฏิเสธ VAA ที่ถูกใช้ไปแล้ว Wormhole ได้เพิ่มการป้องกันเล่นซ้ำในเวอร์ชันถัดมา แต่ในเวอร์ชันที่โจมตีไม่มี ดังนั้น VAA ที่อนุมัติปลอมสามารถนำมาใช้ซ้ำได้หลายครั้ง ทุกการทำงานของสะพานควรขึ้นกับการแมปที่เก็บสถานะ VAA ที่ใช้ (processed_vaas: mapping[bytes32, bool]) ที่อัปเดตอย่างอะตอมมิกในช่วงเริ่มต้นการรัน
4. การใช้ API ที่เลิกใช้เป็นจุดตรวจสอบความปลอดภัยร้ายแรง
ช่องโหว่ Wormhole มาจากการใช้ API ที่เลิกใช้ Solana SDK แจ้งเตือนว่าฟังก์ชัน load_instruction_at เป็น deprecated และมีตัวเลือก _checked ก่อนการโจมตี การไม่อัปเกรดจาก API ที่เลิกใช้ไม่ใช่แค่ปัญหาคุณภาพโค้ดแต่เป็นช่องโหว่ความปลอดภัยที่ผู้โจมตีชอบค้นหาผ่านการอ่าน changelog และเปรียบเทียบคอมมิทที่ยังไม่ได้ดีพลอยกับโค้ดที่ดีพลอยแล้ว การตรวจสอบโปรแกรม Solana ควรสแกนการใช้งาน solana_program::sysvar::instructions::* ทุกตัวที่ไม่ใช่ _checked และแจ้งเตือนเป็น Critical พบได้ในงานตรวจสอบของ Ottersec, Halborn และ Soken หลังปี 2022
5. การแก้ไขความปลอดภัยที่ยังไม่ดีพลอยเป็นแผนที่โจมตีที่สาธารณะ
การแก้ไข load_instruction_at_checked ถูกคอมมิทในคลังข้อมูลสาธารณะของ Wormhole ก่อนการโจมตี นักโจมตีที่มีความรู้และติดตามคลังข้อมูลได้นำการแก้ไขนี้เป็นข้อมูลโจมตีที่เกิดขึ้นจริง กลไกการปล่อยดีพลอยสำหรับโปรแกรมของเหตุการณ์ความปลอดภัยสูงต้องจัดการช่องว่างระหว่าง “รวมเข้ากับ main” และ “ดีพลอยกับ mainnet” เป็นช่วงเวลาสำคัญที่ต้องปิดภายในไม่กี่ชั่วโมง ไม่ใช่หลายวัน
6. ลายเซ็น threshold multisig ไม่สามารถทดแทนการตรวจสอบบัญชีได้
เครือข่าย Guardian ของ Wormhole ประกอบด้วยโหนดอิสระ 19 โหนดในโครงสร้างลายเซ็น threshold ซึ่งทนทาน แต่ไม่มีผลกับการโจมตีนี้เลย การโจมตีหลบเลี่ยงชั้นฉันทามติทั้งหมดโดยการแก้ไขบัญชีที่ verify_signatures อ่าน ลายเซ็น threshold ป้องกันความเสียหายเมื่อตกอยู่ในมือผู้โจมตี แต่ไม่ป้องกันบั๊กที่ไม่เคยขออินพุตจาก Guardian เลย การป้องกันลึกลงไปต้องแน่ใจว่าทุกชั้นของโมเดลความปลอดภัยถูกเรียกใช้ — การควบคุมที่ถูกข้ามคือไม่มีการควบคุม
ความหมายของเรื่องนี้ต่อการตรวจสอบสะพานและความปลอดภัยโปรแกรม Solana
การโจมตี Wormhole แสดงให้เห็นว่าความปลอดภัยสะพานข้ามเครือข่ายเป็นปัญหาหลายชั้น เครือข่าย Guardian อาจแข็งแกร่งทางเข้ารหัส ตรงกับแรงจูงใจทางเศรษฐกิจ สถาปัตยกรรมโปรโตคอลออกแบบดี — แต่แค่การเรียกฟังก์ชันที่เลิกใช้ในโปรแกรมบนเชนเดียว ก็สามารถทำให้ทั้งหมดกลายเป็นโมฆะได้
สำหรับทีมที่พัฒนาบน Solana บทเรียนเรื่องการตรวจสอบบัญชีควรเป็นสากล: ถือว่าพารามิเตอร์ทุกตัวที่ส่งเข้าโปรแกรมเป็นข้อมูลที่เป็นศัตรู ตรวจสอบเจ้าของ, กุญแจ, ตัวแยกประเภท และความยาวข้อมูลก่อนใช้งานบัญชีใดๆ ใช้ wrapper Account<T> จาก anchor framework หรือเทียบเท่าเพื่อตรวจสอบในระดับชนิดข้อมูล แทนการเช็คด้วยตนเอง
สำหรับผู้ออกแบบสะพาน บทเรียนคือการแยกสิทธิ์และยึดสถานะหลัก สิทธิ์การสร้างโทเคนต้องลิงก์กลับไปยังสถานะที่โปรแกรมเป็นเจ้าของและตรวจสอบเอง — ไม่ใช่หลักฐานที่ส่งมาโดย callers ที่ถูกยอมรับโดยไม่มีการตรวจสอบ
Soken ตรวจสอบโปรแกรม Solana ทุกตัวเพื่อค้นหาการใช้ API sysvar ที่เลิกใช้, การพลาดตรวจสอบเจ้าของบัญชี, และช่องว่างการป้องกันการซ้ำซ้อนของ VAA เป็นรายการที่มีลำดับความสำคัญระดับ Critical รูปแบบการโจมตีแบบ Wormhole — ข้ามการตรวจสอบ multisig threshold ด้วยการแก้ไขบัญชีที่ฟังก์ชันตรวจสอบอ่าน — ได้กลายเป็นคลาสการโจมตีที่มีชื่อเรียกในแนวทางการตรวจสอบ Solana ของเรา หากโปรโตคอลของคุณใช้การส่งข้อความข้ามเครือข่ายหรือการสร้างโทเคนห่อหุ้ม ติดต่อเราที่ soken.dev/services-it.html เพื่อปรึกษาการตรวจสอบความปลอดภัยก่อนนำไปใช้งานจริง