BTC
ETH
HTX
SOL
BNB
ดูตลาด
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

การวิเคราะห์การโจมตีการโจรกรรมมูลค่า 9 ล้านเหรียญสหรัฐของ Yearn

ExVul Security
特邀专栏作者
@exvulsec
2025-12-02 06:48
บทความนี้มีประมาณ 3806 คำ การอ่านทั้งหมดใช้เวลาประมาณ 6 นาที
เมื่อวันที่ 1 ธันวาคม 2568 Yearn ถูกโจมตีแบบผสมผสานหลายขั้นตอน ส่งผลให้สูญเสียเงินประมาณ 9 ล้านดอลลาร์ ผู้โจมตีใช้เงินกู้แบบแฟลชเป็นช่องทางในการกู้ยืม โดยอาศัยช่องโหว่ในระบบการตรวจสอบสถานะขั้นสูงสุด การแยกสาขาเชิงตรรกะ และการควบคุมที่แม่นยำของโปรโตคอล เพื่อค่อยๆ จัดการพูลสภาพคล่อง จนในที่สุดก็สามารถสร้าง yETH LP ได้เกือบไม่จำกัดจำนวน และทำให้พูลว่างเปล่า เหตุการณ์นี้เน้นย้ำถึงความเป็นมืออาชีพของการโจมตี DeFi และเผยให้เห็นข้อบกพร่องของระบบในพารามิเตอร์ขอบ ระบบการคำนวณที่สำคัญ และระบบตรวจสอบของโปรโตคอล
สรุปโดย AI
ขยาย
  • 核心观点:Yearn协议遭多阶段组合攻击损失900万美元。
  • 关键要素:
    1. 利用闪电贷撬动初始攻击资金。
    2. 组合利用精度丢失等三个核心漏洞。
    3. 最终实现无限铸造LP代币并掏空资金池。
  • 市场影响:凸显DeFi协议组合漏洞风险,促进行业安全升级。
  • 时效性标注:中期影响

คำนำ

เมื่อวันที่ 1 ธันวาคม 2568 โปรโตคอล Yearn ถูกแฮ็กอย่างซับซ้อนและหลายขั้นตอน ส่งผลให้สูญเสียสินทรัพย์ไปประมาณ 9 ล้านดอลลาร์สหรัฐฯ การโจมตีครั้งนี้ไม่ใช่การโจมตีเพียงครั้งเดียว แต่เป็นการใช้ประโยชน์จากเงินทุนผ่านสินเชื่อแบบแฟลช ใช้ประโยชน์จากข้อบกพร่องเชิงตรรกะหลายประการในโปรโตคอลเพื่อค่อยๆ จัดการพูลสภาพคล่อง จนในที่สุดก็สามารถสร้างโทเค็น LP ที่เกี่ยวข้องกับ yETH ได้เกือบไม่มีที่สิ้นสุด และทำให้พูลสภาพคล่องลดลง

การโจมตีครั้งนี้ใช้เงินกู้ระยะสั้นเป็นเครื่องมือทางการเงินเบื้องต้น และเจาะทะลุการป้องกันของโปรโตคอลไปทีละชั้นผ่านหลายขั้นตอน กระบวนการโจมตีหลักสามารถแบ่งออกเป็นสี่ขั้นตอนหลัก ได้แก่ การเตรียมเงินทุน การจัดการสถานะ การสร้างเหรียญแบบไม่จำกัด และการทำกำไร แต่ละขั้นตอนเชื่อมโยงกันและใช้ประโยชน์จากช่องโหว่เชิงตรรกะในการออกแบบโปรโตคอลอย่างแม่นยำ

การโจมตี Tencent : https://etherscan.io/tx/0x53fe7ef190c34d810c50fb66f0fc65a1ceedc10309cf4b4013d64042a0331156

การวิเคราะห์ทางเทคนิค

ขั้นแรก เราขอยืม wstETH, rETH, WETH และ 0xa35b_ETHx, rETH, wstETH, cbETH จาก Balancer และ Aave ตามลำดับ ผ่านการกู้ยืมแบบแฟลชสองรายการ

ในฟังก์ชันเรียกกลับการกู้ยืมแบบแฟลช ETH ที่ยืมมาจะถูกฝากเข้า Tornado.Cash: 100 ETH เพื่อผสมกับ 1100 ETH จากนั้น ฟังก์ชันถอนเงิน Tornado.Cash: 100 ETH จะใช้เพื่อถอน 100 ETH ไปยังสัญญาอันตราย 0x3e8e7533dcf69c698Cf806C3DB22f7f10B9B0b97 และเรียกใช้ฟังก์ชันสำรอง

ในฟังก์ชัน fallack เราจะเห็นว่าการแลกเปลี่ยนครั้งสุดท้ายในภาพด้านล่างมีค่าเท่ากับค่า remove_liquidity ในขั้นตอนถัดไป อนุมานได้ว่าขั้นตอนก่อนหน้านี้ทั้งหมดคือการแลกเปลี่ยนสินทรัพย์ที่ได้จากการกู้ยืมแบบแฟลช (flash loan) เป็นโทเค็น LP จำนวนมากในกลุ่ม stableswap yETH ผ่านการดำเนินการต่างๆ เช่น การแลกเปลี่ยน เพื่อเตรียมพร้อมสำหรับการโจมตีครั้งต่อไป

เมื่อถึงจุดนี้ กระบวนการโจมตีหลักจะเริ่มขึ้นอย่างเป็นทางการ

1. ขั้นแรก โทเค็น LP ทั้งหมดที่ได้รับจากการแลกเปลี่ยนข้างต้นจะถูกทำลายและแปลงเป็นสินทรัพย์พื้นฐาน 8 รายการในกลุ่มตามการจัดสรรส่วนแบ่งผ่านฟังก์ชัน remove_liquidity ของกลุ่ม stableswap ที่ถ่วงน้ำหนัก yETH

สามารถเข้าใจตรรกะของฟังก์ชัน remove_liquidity ได้ดังนี้: โดยถือว่ามีโทเค็น LP ทั้งหมด 10,000 โทเค็นในพูล และคุณทำลายโทเค็น LP จำนวน 416.37 โทเค็น LP สัดส่วนของคุณคือ: 416.37 / 10,000 = 4.16%

จากนั้น สำหรับสินทรัพย์แต่ละรายการ โดยถือว่ามี 1,000 wstETH (ยอดคงเหลือเสมือน prev_vb) ในกลุ่ม ยอดคงเหลือเสมือนที่คุณสามารถถอนได้คือ: dvb = 1,000 * 416.37 / 10,000 = 41.637 wstETH ซึ่งจากนั้นจะหารด้วยอัตราแลกเปลี่ยนเพื่อแปลงเป็นจำนวนโทเค็นจริง

2. ประการที่สอง โดยการเรียก `add_liquidity` ซ้ำๆ กัน พูลด้านเดียวจะถูกฉีดเข้าไป มีพารามิเตอร์ `_amounts` ทั้งหมด 8 ตัว ซึ่งแต่ละตัวจะสอดคล้องกับจำนวนสินทรัพย์ต่างๆ ที่จะฉีดเข้าไป พบว่าในลูปก่อนหน้า index3[rETH token], index6[wOETH token] และ index7[mETH token] ถูกป้อนเป็น 0 ทั้งหมด ซึ่งหมายความว่าโทเค็นทั้ง 3 ตัวนี้จะไม่ถูกเพิ่มเข้าไปทุกครั้งที่มีการเพิ่มสภาพคล่อง

การฉีดสินทรัพย์ฝ่ายเดียวและการถอนโทเค็นออกจากกลุ่มในลักษณะที่อธิบายไว้ข้างต้น จะทำให้ช่องว่างปริมาณระหว่าง rETH, w0 ETH, mETH และโทเค็นอื่นๆ ในกลุ่มกว้างขึ้นอย่างไม่เป็นธรรมชาติ

3. ต่อไปนี้ โทเค็น rETH จำนวนมากจะถูกฉีดเข้าไปฝ่ายเดียว ตามด้วยขั้นตอนสำคัญในการลบสภาพคล่อง แต่มีจำนวนเท่ากับ 0

เหตุใดจึงถอนโทเค็นได้ 0 โทเค็น สาเหตุมาจากการใช้งานภายในของ remove_liquidity

ฟังก์ชัน remove_liquidity จะไม่ทำการประมวลผลแบบลัดวงจรสำหรับธุรกรรมที่มีค่า 0 แต่จะยังคงดำเนินการลูปการคำนวณ vb_prod ทั้งหมด และคำนวณและอัพเดตสถานะ packed_pool_vb ทั่วโลกโดยอิงตามความแตกต่างของปริมาณโทเค็นในพูลที่สร้างขึ้นโดยเทียมดังที่กล่าวไว้ข้างต้น

4. จากนั้นเรียกใช้ฟังก์ชัน update_rates เพื่ออัปเดตเฉพาะอัตราส่วนพูลของ index6[wOETH] และสุดท้ายเรียกใช้ remove_liquidity เพื่อดึงโทเค็นออกจากพูล ณ จุดนี้ ปริมาณ W0 ETH ในพูลเกือบจะหมดไปแล้ว

5. ในทำนองเดียวกัน ให้บีบส่วนแบ่งของ index6[w0 ETH] และ index7[mETH] ในพูลด้วยวิธีเดียวกัน โปรดทราบว่าหลังจากอัปเดต index6 สองครั้งแรกแล้ว จะใช้ remove_liquidity เพื่อถอนโทเค็น ในขณะที่ index7[mETH] ได้รับการอัปเดตแล้วเท่านั้นและยังไม่ได้ถอนออก

การเพิ่มโทเค็นจำนวนมหาศาลลงในพูลด้านเดียวและการดึงโทเค็นทั้งหมดออกจากพูลอย่างต่อเนื่อง ทำให้อัตราส่วนของ W0 ETH ต่อ mETH ในพูลนั้นแทบจะกลายเป็นศูนย์

ณ จุดนี้ สัญญาอันตรายใหม่ 0xADbE952eBB9b3e247261d2E3b96835f00f721f8E จะถูกสร้างขึ้น และโทเค็นทั้งหมดจะถูกโอนไปยังสัญญานี้ โปรดทราบว่าโทเค็น LP ที่ได้รับจากการเพิ่ม rETH ในขั้นตอนก่อนหน้านี้ฝ่ายเดียวจะไม่ถูกแปลงเป็นโทเค็นพื้นฐาน แต่ถูกโอนไปยังสัญญาอันตรายใหม่ด้วยเช่นกัน

การโจมตีครั้งก่อนได้อัปเดต index7[mETH] ใน update_rates แต่โทเค็นที่ไม่ถูกถอนออกจะถูกถอนออกที่นี่โดยการเรียกใช้ remove_liquidity ณ ขณะนี้ ส่วนแบ่งของ index6[w0 ETH] ในพูลมีขนาดเล็กมาก และส่วนแบ่งของ index7[mETH] ก็เล็กยิ่งกว่านั้นอีก

ณ จุดนี้ อัตราส่วนโทเค็นในพูลไม่สมดุลอย่างรุนแรง ผู้โจมตีเรียกใช้ add_liquidity อีกครั้งเพื่อเพิ่มสภาพคล่อง ทำให้ได้รับโทเค็น LP จำนวนมากในอัตราส่วน [1, 1, 1, 1, 1, 1, 1, 9]

ณ จุดนี้ ผู้โจมตีได้โทเค็น LP จำนวนมาก จากนั้นจึงใช้วิธีต่างๆ เช่น การแลกเปลี่ยนและไถ่ถอน เพื่อทำกำไรและชำระค่าธรรมเนียมสินเชื่อแบบแฟลช

การตรวจสอบการโจมตี

การโจมตีนี้เป็นการโจมตีแบบผสมผสานหลายขั้นตอนที่ซับซ้อน ซึ่งผู้โจมตีใช้ประโยชน์จากช่องโหว่หลักสามจุดในสัญญา pool.vy ได้แก่ การสูญเสียความแม่นยำ การลอกผลตอบแทน และการเริ่มต้นการจัดหาเป็นศูนย์

ระยะที่ 1: การสร้างความไม่สมดุลขั้นรุนแรง

  • การดำเนินการ: ผู้โจมตีจะเรียก add_liquidity ซ้ำๆ แต่หลีกเลี่ยงดัชนี 3 (rETH), ดัชนี 6 (wOETH) และดัชนี 7 (mETH) โดยเจตนา
  • วัตถุประสงค์: เพื่อสร้างความไม่สมดุลในอัตราส่วนสินทรัพย์ภายในกลุ่มโดยไม่เป็นธรรม
  • ขั้นตอนสำคัญ: จากนั้นฉีด rETH จำนวนมากในฝ่ายเดียว
  • ผลที่ตามมา: ส่งผลให้ช่องว่างเชิงปริมาณระหว่าง rETH และสินทรัพย์อื่นๆ (โดยเฉพาะ wOETH และ mETH) กว้างขึ้นอย่างมาก ส่งผลให้เกิดเงื่อนไขทางคณิตศาสตร์ที่ทำให้สูญเสียความแม่นยำ

ขั้นตอนที่สอง: การกระตุ้นและล็อคข้อผิดพลาด

  • การดำเนินการ: เรียก remove_liquidity(_amount=0)
  • หลักการ:

`remove_liquidity` จะไม่ทำการลัดวงจรสำหรับปริมาณ 0

แม้จะไม่มีการโอนเงิน สัญญาก็ยังคงดำเนินการคำนวณวนรอบทั้งหมดของ vb_prod

ภายใต้ความไม่สมดุลของน้ำหนักที่รุนแรง ฟังก์ชัน _pow_down จะสร้างข้อผิดพลาดในการปัดเศษลงอย่างมีนัยสำคัญ

สัญญาจะเขียนค่าข้อผิดพลาดที่เล็กกว่าของ vb_prod ลงในสถานะทั่วโลก packed_pool_vb

  • โดยพื้นฐานแล้ว นี่คือการโจมตีสถานะ "ต้นทุนเป็นศูนย์" โดยผู้โจมตีสามารถเปลี่ยนแปลงมูลค่าทางบัญชีของกลุ่มได้สำเร็จโดยไม่ต้องเสียค่าใช้จ่ายใดๆ

ขั้นตอนที่สาม: การหักรายได้และการดึงส่วนแบ่งทางการตลาด

  • ดำเนินงาน:

update_rates([6]) (อัปเดตอัตราแลกเปลี่ยน wOETH)

remove_liquidity (ลบสินทรัพย์)

update_rates([7]) (อัปเดตอัตราแลกเปลี่ยน mETH)

  • หลักการ:

`update_rates` จะทริกเกอร์ `_update_supply` เนื่องจาก `vb_prod` ถูกระงับการใช้งานอย่างมีเจตนาร้ายก่อนหน้านี้ ระบบจึงตัดสินผิดพลาดว่ามูลค่าพูลลดลง และด้วยเหตุนี้จึงทำลายโทเค็น LP ที่ถือครองโดยสัญญา staking เพื่อปรับสมดุลบัญชี

ผู้โจมตีใช้ประโยชน์จาก remove_liquidity เพื่อเก็งกำไรก่อนและหลังการอัปเดตอัตราแลกเปลี่ยน ส่งผลให้ wOETH และ mETH ค่อยๆ ลดลง

  • ผลลัพธ์: สัญญาการเดิมพันจำนวนมากถูกทำลาย ส่วนแบ่ง LP ของผู้โจมตีเพิ่มขึ้นแบบพาสซีฟ และอุปทานรวมของกลุ่มถูกผลักไปที่ 0

ระยะที่สี่: อุปทานเป็นศูนย์, การผลิตไม่จำกัด

  • สถานะที่มีอยู่ก่อน: หลังจากการดำเนินการข้างต้น พูลจะถูกล้างออกไป อุปทานทั้งหมดอยู่ใกล้ 0 และความสมดุลของ wOETH และ mETH ต่ำมาก
  • การดำเนินการ: add_liquidity พารามิเตอร์คือ _amounts=[1, 1, 1, 1, 1, 1, 1, 1, 9]
  • หลักการ:

เมื่อ prev_supply ≈ 0 สูตรวนซ้ำสำหรับ _calc_supply จะล้มเหลวเมื่อจัดการกับค่าที่เล็กมาก (1 wei, 9 wei)

สัญญาดังกล่าวคำนวณจำนวนโทเค็น LP ที่ต้องผลิตอย่างไม่ถูกต้อง

  • ผลลัพธ์: ผู้โจมตีได้รับโทเค็น LP yETH จำนวน 235,443 รายการจากอากาศ

สรุป

การโจมตีแบบ Yearn เผยให้เห็นข้อบกพร่องหลายประการในโปรโตคอล DeFi ทั้งในด้านการตรวจสอบตรรกะในสถานการณ์ edge การควบคุมความแม่นยำในการคำนวณเชิงตัวเลข และการป้องกันความเสี่ยงจากช่องโหว่หลายชุด รูปแบบการโจมตีของผู้โจมตี ซึ่งใช้การกู้ยืมแบบแฟลชเป็นเครื่องมือ การใช้ประโยชน์จากช่องโหว่แบบผสมผสานเป็นแกนหลัก และการปกปิดเงินทุน แสดงให้เห็นถึงแนวโน้มปัจจุบันของความเป็นมืออาชีพและความซับซ้อนในการโจมตี DeFi บทเรียนสำคัญที่ได้เรียนรู้จากการโจมตีครั้งนี้ ได้แก่ ประการแรก โปรโตคอลจำเป็นต้องเสริมสร้างการตรวจสอบตรรกะสำหรับสถานการณ์ edge เช่น "จำนวนเงินเป็นศูนย์" และ "ความไม่สมดุลอย่างรุนแรง" เพื่อหลีกเลี่ยงความเสี่ยงจากการถูกแทรกแซงสถานะเนื่องจากการขาดการจัดการแบบลัดวงจร ประการที่สอง จำเป็นต้องแก้ไขการสูญเสียความแม่นยำภายใต้อัตราส่วนที่รุนแรงในการคำนวณเชิงตัวเลข และต้องปรับปรุงตรรกะการคำนวณของฟังก์ชันหลัก เช่น `_pow_down` โปรโตคอล Balancer เคยประสบเหตุการณ์ด้านความปลอดภัยเนื่องจากการสูญเสียความแม่นยำ ซึ่งเป็นเรื่องเตือนใจ ประการที่สาม ควรจัดตั้งระบบตรวจสอบความเสี่ยงแบบหลายมิติเพื่อแจ้งเตือนการดำเนินการที่น่าสงสัย เช่น การอัดฉีดสภาพคล่องด้านเดียวความถี่สูง และการอัปเดตอัตราแลกเปลี่ยนที่ผิดปกติ สำหรับอุตสาหกรรม DeFi ทั้งหมด เหตุการณ์นี้พิสูจน์อีกครั้งว่าความปลอดภัยของโปรโตคอลไม่เพียงแต่ต้องแก้ไขช่องโหว่เฉพาะจุดเท่านั้น แต่ยังต้องป้องกันการโจมตีที่รวมช่องโหว่หลายจุดจากมุมมองแบบองค์รวม ควบคู่ไปกับการเสริมสร้างการติดตามและสกัดกั้นกระแสเงินทุนของผู้โจมตี เพื่อปรับปรุงขีดความสามารถในการป้องกันความปลอดภัยโดยรวมของอุตสาหกรรม

ความปลอดภัย
DeFi
yearn
ยินดีต้อนรับเข้าร่วมชุมชนทางการของ Odaily
กลุ่มสมาชิก
https://t.me/Odaily_News
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
บัญชีทางการ
https://twitter.com/OdailyChina
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
ค้นหา
สารบัญบทความ
ดาวน์โหลดแอพ Odaily พลาเน็ตเดลี่
ให้คนบางกลุ่มเข้าใจ Web3.0 ก่อน
IOS
Android