Ngày 14 tháng 10 năm 2021, vụ hack Indexed Finance đã rút 16 triệu USD từ Indexed Finance – một giao thức chỉ số trên Ethereum – trong vòng chưa đầy 25 phút, không đánh cắp bất kỳ private key nào và không phá vỡ mật mã. Người tấn công đã sử dụng một gói vay flash duy nhất trị giá khoảng 50 triệu đô la để tạm thời điều chỉnh giá hiện hành trong các nhóm chỉ số kiểu Balancer của Indexed, sau đó yêu cầu chức năng joinPool của các nhóm đó để định giá một khoản gửi nhỏ với giá định giá đó. Các nhóm, đã xem số dư token trực tiếp của họ như một oracle trung thực cho giá của cổ phần LP, đã phát hành quá nhiều token LP với lượng đầu tư quá nhỏ. Người tấn công sau đó đã đốt cháy các cổ phần LP bị phồng lên với giá thực và bỏ đi với sự khác biệt. Một bộ tăng cường thứ hai, yên tĩnh hơn, đã làm trầm trọng thêm tình hình: giao thức ghi nhận các khoản gửi bằng số lượng token được yêu cầu, không phải số lượng thực sự nhận được, do đó bất kỳ phí chuyển giao hoặc đốt cháy giảm giá trên token gửi đều âm thầm làm tăng số lượng token bị phát hành quá nhiều.
Indexed Finance Là Gì và Vì Sao Thiết Kế Của Nó Nguy Hiểm
Indexed Finance, được phát hành vào cuối năm 2020 trên Ethereum bởi nhà phát triển Dillon Kellar, cung cấp các token chỉ số được quản lý theo cách không tham gia – hãy nghĩ về các ETF tiền điện tử. Mỗi chỉ số (DEFI5, CC10, DEGEN, FFF) không phải là một kho hoặc hợp đồng giỏ chứa các token với trọng lượng cố định. Nó là một Balancer V1 fork: một nhóm nhà tạo thị trường tự động (BPool) trong đó mỗi token cơ sở có trọng lượng mục tiêu và nhóm này được cân bằng lại thông qua reweighTokens để theo dõi một chỉ số. Ví dụ, những người sở hữu DEFI5 không giữ 5 token – họ giữ cổ phần LP của một nhóm có trọng lượng chứa AAVE, COMP, MKR, SNX và UNI với trọng lượng phản ánh chỉ số vốn hóa thị trường.
Vào tháng 10 năm 2021, Indexed giữ tổng giá trị khoảng 30 triệu USD bị khóa trong các pool của nó – mức thấp so với Poly hoặc Ronin, nhưng tập trung. Ba đặc điểm này đã khiến giao thức trở thành mục tiêu bị thao túng kinh tế khá bất thường.
Thứ nhất, nó là một fork của Balancer mà không có các cảnh báo của Balancer. Các tài liệu của Balancer cảnh báo: không sử dụng joinPool với giá trị cân bằng tại chỗ đối với các token có phí chuyển đổi, và không thể hiện calcPoolOutGivenSingleIn cho các người gọi không đáng tin cậy trong các pool biến động. Nó kế thừa BMath.sol và công thức poolOut = poolSupply * ((balanceIn + amountIn)/balanceIn)^weight - 1, nhưng sử dụng các pool như các máy tính toán giá trị tài sản net cho một sản phẩm chỉ số – một mô hình đe dọa nơi việc điều chỉnh giá tại chỗ là một lỗi đánh giá, không chỉ là sự trượt giá.
Thứ hai, nó được thiết kế để không cần oracle. Mặt khác với các giao thức cho vay mà ít nhất cũng tham khảo Chainlink, Indexed lấy giá cổ phiếu LP hoàn toàn từ các tài khoản trên chuỗi của nó thông qua getBalance(token). Ai có thể di chuyển các tài khoản đó – ngay cả trong một giao dịch duy nhất – cũng có thể di chuyển giá cả.
Thứ ba, nó chưa được kiểm toán về rủi ro cấu trúc. Sigma Prime đã kiểm toán các hợp đồng Controller và Pool vào tháng 12 năm 2020 và nhận thấy các vấn đề liên quan đến xử lý phí chuyển đổi và sử dụng spot từ một nguồn duy nhất như là những phát hiện thông tin. Đội ngũ đã chấp nhận rủi ro đối với các tài sản hỗ trợ DEFI5/CC10 bao gồm các token có hành vi transferFrom không tiêu chuẩn. Không có thử nghiệm tích hợp kết hợp vay flash → sai lệch khối lượng → độ lệch deflationary → joinPool.
Dòng Thời Gian: 25 Phút Để Rút Sạch, 72 Giờ Để Rửa Tiền
Toàn bộ cuộc tấn công phù hợp với một cửa sổ khối Ethereum duy nhất, với quá trình rửa tiền kéo dài trong ba ngày.
14 tháng 10, 2021, 15:42 UTC (block 13416666) — Hợp đồng của kẻ tấn công 0xba5edB19b291cc484cA15514D663Fc331A67A4A được triển khai, được tài trợ bằng 10 ETH từ Tornado Cash — đường ray không rõ ràng cho bước duy nhất cần ẩn.
15:55 UTC (block 13416688) — Cách thức tấn công giao dịch #1 nhắm vào đồng DEFI5 (~$6,9 triệu bị lấy đi). Người tấn công flash loan ~$48 triệu DAI, WETH và WBTC thông qua Aave V2 và dYdX, sử dụng một lượng lớn để làm biến dạng các tài khoản nội bộ của DEFI5 (đẩy mức tài khoản của một token lên cao để khiến token khác trông rẻ), gọi joinPool với một lượng nhỏ token rẻ, nhận được cổ phần LP DEFI5 bị phình lên, đảo ngược biến dạng, sau đó gọi exitPool để đốt cổ phần LP với giá trị thực — lợi nhuận ròng ~$6,9 triệu trong các tài sản liên quan (AAVE, COMP, MKR, SNX, UNI). Việc flash loan được trả trong giao dịch tương tự.
16:02 UTC – Cấu trúc giao dịch #2 nhắm vào CC10 pool (~$6.1 triệu). Cấu trúc tương tự, nhưng trọng lượng được thiết lập khác nhau: CC10 có trọng lượng lớn hơn trong WBTC và ETH, do đó, token duy nhất được thu thập nhiều nhất là WBTC. Người tấn công sử dụng lại cơ chế flash-loan với đường dẫn khác nhau trên Uniswap V2 / Sushiswap để chuyển số dư hiện hành của CC10.
16:18 UTC – Cấu trúc giao dịch #3 tấn công vào gói NDX / FFF / DEGEN (~ 3,2 triệu USD tổng cộng). Hệ thống ví NDX và các hệ thống nhỏ hơn có chung đường dẫn mã lỗ hổng _pullUnderlying + calcPoolOutGivenSingleIn. Kết quả lợi nhuận nhỏ hơn vì TVL nhỏ hơn, nhưng phương pháp tương tự.
16:30 UTC — Dillon Kellar tweet "đang điều tra", Indexed multisig ngừng hoạt động của Controller, ngăn chặn các cuộc gọi joinPool tiếp theo. Các nhóm còn lại (bao gồm một phần FFF không được tác động) được dọn sạch bởi nhóm vào một mô-đun an toàn.
Ngày 14 tháng 10 tối — Indexed đăng một bài viết sơ bộ: "Chúng tôi đã xác định một vấn đề về việc ghi sổ 'joinPool'," yêu cầu các sàn giao dịch báo cáo về người tấn công '0xba5ed...', và gửi một lời đề nghị thưởng 10% thông qua tin nhắn dữ liệu vào địa chỉ của người tấn công qua Etherscan. Người tấn công không trả lời.
15 tháng 10 — Bản phân tích toàn diện được công bố, thiệt hại được tính là $16,042,214 (đã được điều chỉnh) — Giá trị thị trường của PeckShield ước tính là ~$16,5 triệu với giá ETH ~$3,800. Mật độ TVL còn lại (~$12 triệu) được chuyển sang SafePool được bảo vệ. Thảo luận về bồi thường bắt đầu: chụp ảnh tại khối 13416665, nợ theo tỷ lệ phần trăm.
16–18 tháng 10 — Người tấn công thực hiện việc rửa tiền: các token cơ sở → WETH thông qua máy tổng hợp 1inch → Tornado Cash trong 100 lô 1 ETH, tổng cộng khoảng 1.200–1.500 ETH trong vòng 72 giờ (SlowMist, PeckShield đồng ý về quy mô; số lượng chính xác thay đổi tùy theo giá). Không có khoản tiền nào được trả lại. Không có khả năng đóng băng Tornado — trái với USDT của Poly, số tiền trộm trong vụ tấn công tài chính được chỉ định là các token quản trị và biến động mà không có nút tắt phát hành.
Số liệu: Từ đâu mà số tiền 16 triệu USD đến và tại sao khoản vay lớn hơn thế
Số tiền vay flash chỉ là một con số nhỏ so với lợi nhuận – một đặc điểm của các hành vi lừa đảo giá khi vay tiền là người quyết định giá, không phải là hành vi trộm cắp.
| Pool | Bị đánh cắp (Indexed chính thức) | PeckShield ước tính | Tài sản rời khỏi pool |
|---|---|---|---|
| DEFI5 (Top 5 DeFi) | ~$6,9 triệu | 7,1 triệu USD | AAVE, COMP, MKR, SNX, UNI (bộ sưu tập 5 token có trọng số) |
| CC10 (Top 10) | ~$6.1 triệu | 6,3 triệu USD | WBTC (lớn nhất), WETH, LINK, UNI, AAVE, COMP |
| NDX / DEGEN / FFF | ~$3.0 triệu | 3,1 triệu USD | Token quản trị NDX + các nền tảng hồ sơ chủ đề |
| Tổng | ~$16.0 triệu | ~$16,5 triệu | 16–16,5 triệu đô la tùy thuộc vào giá ETH 3.750–3.850 đô la |
Anatomi của khoản vay flash (trường hợp giao dịch đại diện #1): ~$48,6 triệu USD, bao gồm DAI (~$18 triệu), WETH (~$15 triệu), USDC (~$10 triệu), WBTC (~$5 triệu) thông qua Aave V2 + dYdX "flashLoan". Được trả bằng phí ~$49.000 trong cùng một giao dịch atom. Tỷ lệ lợi nhuận thuần: ~33% của giá trị có thể bị rủi ro trong khoảng thời gian ~30 giây.
Kinh tế học của kẻ tấn công: Cấu hình + nguồn tài chính của Tornado: 10 ETH (~$38K). Chi phí gas cho 3 giao dịch khai thác: ~2 ETH. Tỷ lệ lợi nhuận thuần: ~4.200 ETH tương đương (~$16 triệu với giá 3.800 USD). Tổng: ~4.188 ETH → được rửa sạch thông qua Tornado. ROI: ~350x.
Tại sao là 16 triệu USD, không phải 30 triệu USD TVL? Người tấn công chỉ rút tiền từ các pool nơi chu kỳ skew → join → unskew → exit có lợi nhuận sau khi tính phí trượt và phí cho vay flash. Một pool thứ tư (FFF tranche) có lượng likidty quá ít để chu kỳ skew có thể mang lại hiệu quả kinh tế, vì vậy người tấn công bỏ qua nó – tối ưu hóa lợi nhuận hợp lý, không phải hạn chế cơ hội.
Nguyên nhân: Sử dụng token cho vay Flash LP thông qua các tài khoản hiện hành và kế toán giảm giá
Hacker tấn công tài chính này không phải là lỗi reentrancy, không phải là lỗi kiểm soát truy cập, và cũng không phải là một chìa khóa bị đánh cắp. Đó là một vi phạm bất biến kinh tế: giá cổ phiếu LP của kho được tính từ các số dư hiện tại có thể bị điều khiển và một biên nhận token không được kiểm tra.
Kế toán cân bằng đã trở thành một lời tiên tri
Các nhóm có chỉ số sử dụng BMath.calcPoolOutGivenSingleIn:
` poolOut = poolSupply * ((balanceIn + amountIn) / balanceIn) ^ weight - 1 `
balanceIn là số dư token hiện tại của kho (getBalance(token)), amountIn là số lượng tham gia, weight là trọng số mục tiêu đã được chuẩn hóa (ví dụ, 0.20 cho kho có trọng số bằng nhau với 5 token). Công thức tạo ra token LP theo tỷ lệ với mức tăng số dư của token tham gia.
Điều này là hợp lý khi balanceIn phản ánh một thị trường công bằng - nó là oracle. Nó bị phá vỡ khi một kẻ tấn công có thể đặt balanceIn thành bất kỳ giá trị nào cho một giao dịch.
Đường đi bộ bằng bê tông (DEFI5):
- Trước khi tấn công, DEFI5 giữ 1,000 AAVE và 1,000 COMP với trọng lượng bằng nhau, cung cấp 10,000 LP. Giá LP hợp lý: 1 LP = 0.20 AAVE + 0.20 COMP.
Bước 2 của khoản flash loan – không phải để đánh cắp, mà là để đặt giá mà nhóm sẽ sử dụng để định giá khoản gửi của kẻ tấn công.
Lỗi thứ hai: Được ghi nhận > Được nhận
Tự độc lập, _pullUnderlying của Indexed đã thực hiện:
`solidity function _pullUnderlying(address token, address from, uint amount) internal { IERC20(token).transferFrom(from, address(this), amount); // no balance delta check } `
Tiếp theo, _joinPool sử dụng amount (công thức đầu vào yêu cầu) để tính toán poolOut. Đối với các token có phí chuyển giao / giảm giá, sẽ đốt 2–5% trong mỗi giao dịch, nhưng pool thực tế nhận được amount * (1 - fee), nhưng tạo LP như thể nó nhận được toàn bộ amount. BlockSec tính toán điều này là một 3–5% quá nhiều tạo ra mỗi lần tham gia – nhỏ một mình, nhưng nó tích lũy với nhân hệ số lệch điểm: một quá nhiều tạo ra 40x trở thành 41.6x với 4% đốt, tăng thêm ~$400K cho $16M.
Cách khắc phục cho cả hai là một quy tắc: đo lường, không tin tưởng.
`solidity uint balBefore = IERC20(token).balanceOf(address(this)); IERC20(token).transferFrom(from, address(this), amount); uint received = IERC20(token).balanceOf(address(this)) - balBefore; require(received > 0, "zero transfer"); poolOut = calcPoolOutGivenSingleIn(balBefore, weight, poolSupply, received); // and price against TWAP, not spot `
Vì Sao Oracle LP Spot Thất Bại
Các kỹ sư thường hỏi: tại sao không có kiểm toán nào phát hiện ra "tài khoản là oracle"? Vì trong một bể cân bằng bình thường, tài khoản là thị trường – bể là sàn giao dịch, do đó, việc can thiệp vào tài khoản của nó sẽ tốn vốn mà các nhà giao dịch kiếm lại. Ba điều làm cho Indexed khác biệt.
Semantik chỉ số đã thay đổi hợp đồng oracle. Giá LP của một bể Balancer nên phản ánh giá giao dịch của nó. Giá LP của một bể chỉ số nên phản ánh giá trị tài sản ròng (NAV) – tổng trọng số của các tài sản hỗ trợ theo giá thị trường bên ngoài. Indexed sử dụng cân bằng nội bộ cho cả hai, làm tan rã hai oracle thành một. Khi giá giao dịch khác biệt với NAV (ví dụ, trong trường hợp lệch đột ngột), giá LP giao dịch nên quay trở lại – giá NAV nên tham khảo Chainlink/TWAP, không phải getBalance.
Cập nhật trọng lượng làm tăng sai lệch. Các nhóm có chỉ mục gọi reweighTokens theo lịch trình để theo dõi chỉ mục. Khi gần cân bằng lại, trọng lượng đang được cập nhật – trọng lượng mục tiêu của một token có thể là 0,35 so với 0,20. Độ bội số ^weight là siêu tuyến tính, do đó, cùng một sai lệch cân bằng sẽ tạo ra nhiều LP hơn khi trọng lượng cao. Người tấn công đã định thời điểm giao dịch #1 để trùng khớp với một lần reweigh đang chờ, thu được lợi nhuận thêm khoảng 6% (PeckShield).
Không có sự trượt hoặc giới hạn tỷ lệ trên joinPool. Một joinPool đơn lẻ có thể phát hành 15% nguồn cung. Balancer bản thân giới hạn số lần join đơn lẻ ở mức trượt ~50% hoặc yêu cầu minPoolOut. Indexed không có minPoolOut được áp dụng trên đường dẫn Controller mà kẻ tấn công sử dụng – họ đã chỉ định poolAmountOut = 1 (dust), điều này không bao giờ bị đảo ngược ngay cả khi phát hành quá mức 40 lần. Một require(poolOut <= poolSupply * 0.02) sẽ hạn chế lợi nhuận ở mức ~300.000 USD và làm cho khoản vay không có lợi nhuận.
Đây là nợ của fork Balancer: sao chép BMath mà không có danh sách kiểm tra triển khai ("không thể lộ ra joinPool cho các nhà thiết lập giá nguyên tử, thực hiện TWAP, kiểm tra nhận, hạn chế kích thước join đơn lẻ").
Kẻ Tấn Công và Dấu Vết Rửa Tiền
Người tấn công là một người duy nhất hoạt động theo hợp đồng tùy chỉnh 0xba5ed...a67A.
- Tiền vốn: 10 ETH từ Tornado Cash – không phải CEX, không phải faucet. Đây là hành động cố ý để che giấu nguồn gốc, phù hợp với nghiên cứu trước đó (hợp đồng được xác minh trên Etherscan trong vòng 6 giờ, cho thấy đã thử nghiệm trên một fork).
Tại sao không có việc trả lại tiền theo cách hợp pháp? Có hai lý do. Thứ nhất, trái với 611 triệu USD stablecoin của Poly, tiền thu được từ cuộc tấn công tài chính có chỉ số không thể đóng băng – WBTC là mã thông báo duy nhất có thể đóng băng một phần (BitGo), và kẻ tấn công đã đổi ra WBTC trước. Không có nhà phát hành nào có thể ngăn chặn việc lấy tiền. Thứ hai, số tiền ($16 triệu) có thể rửa tiền – Tornado Cash có thể hấp thụ nó theo từng lô, trái với 600 triệu USD của Poly mà không có máy trộn nào có thể xử lý mà không mất nhiều năm. Kẻ tấn công không phải đối mặt với bất kỳ mưu đồ theo dõi nào có thể khiến họ phải đàm phán. Indexed đã cung cấp 10% ($1,6 triệu) thông qua tin nhắn trên Etherscan – nhưng bị bỏ qua.
Phản Ứng, Bồi Thường và Vì Sao Giao Thức Không Phục Hồi
Tác động của Indexed trên chuỗi được thực hiện nhanh chóng; tuy nhiên, sự phục hồi kinh tế của nó không được như vậy.
Ngày 0: Đầu quản lý bị ngừng hoạt động thông qua 3-of-5 multisig (EOA 0x4e...). Các kho chứa còn lại được giải phóng sang SafePool (một lớp bao phủ được bảo vệ, cho phép sử dụng joinPool nhưng không cho phép exitPool). Người dùng vẫn có thể thoát ra với NAV hợp lý – không có thêm thiệt hại sau 16:30 UTC.
Tuần 1: Báo cáo hậu quả được công bố, nguyên nhân được xác nhận là "manipulation token vay flash + xử lý giảm giá", và các sửa đổi được hứa hẹn: kế toán delta tài khoản + oracle TWAP + giới hạn joinPool. Sửa đổi này là chính xác nhưng đã quá muộn.
Tháng 2: Chương trình bồi thường: chụp ảnh tại khối 13416665 (trước khi bị hack), yêu cầu bồi thường theo tỷ lệ phần trăm trên một nhóm DEFI5/CC10 được cung cấp với số dư trong kho (~4 triệu USD) cộng với các mã token nợ dNDX đại diện cho khoảng trống 16 triệu USD. Tỷ lệ giảm hiệu quả: ~50% – các chủ sở hữu đã nhận lại một nửa giá trị NAV trước khi bị hack trong các tài sản có giá trị, một nửa trong một mã token nợ quản trị được giao dịch với giá 0,15 USD. NDX, mã token quản trị, đã giảm từ 12 USD xuống 0,40 USD vào giữa năm 2022 (-97%).
Tại sao không có V2: V2 được công bố (Chainlink TWAP, bảo vệ phí khi chuyển giao, kết nối có giới hạn) nhưng chưa bao giờ đạt được mainnet với TVL. Đội ngũ đã nêu lý do là "thiếu niềm tin của người dùng vào mô hình index-as-AMM" và chuyển sang công việc tư vấn. Quy trình hiện đang bị ngừng hoạt động hiệu quả – một nghiên cứu trường hợp về cách một cuộc tấn công 16 triệu đô la có thể là nguy hiểm khi TVL đạt 30 triệu đô la, nơi một khoản lợi nhuận 611 triệu đô la (Poly) có thể tồn tại với TVL 600 triệu đô la do sự đồng thuận xã hội và việc đóng băng stablecoin mang lại lợi thế mà Indexed không có.
Bài Học: 5 Lớp Phòng Thủ Đã Có Thể Ngăn Chặn Vụ Hack Indexed Finance
1. Giá cổ phiếu LP so với TWAP, không phải là số dư hiện tại. Không bao giờ sử dụng getBalance như một oracle khi cân bằng có thể bị sai lệch một cách đồng bộ. Thay thế calcPoolOutGivenSingleIn(balance) bằng calcPoolOutGivenSingleIn(twapPrice * totalSupply), nơi twapPrice được lấy từ Chainlink hoặc TWAP Uniswap V3 trong 30 phút. TWAP trong 30 phút không thể được di chuyển 40 lần trong một khối, do đó, số dư quá nhiều sẽ sụp đổ từ 40 lần thành ~1.001 lần.
2. Tài khoản theo nhận, không phải yêu cầu. Sau mỗi transferFrom, đo lường balanceAfter - balanceBefore và so sánh với received, không phải là amount. Một dòng ngăn chặn hiệu ứng tăng giảm 3-5% và, quan trọng hơn, làm cho token được tính phí khi chuyển tiền an toàn để được list - là giải pháp thực sự của Indexed. Danh sách đánh giá của trợ lý Yearn coi điều này là bắt buộc; hãy sao chép mẫu đó.
3. Thực hiện giới hạn trượt và kết hợp đơn trong Controller. Yêu cầu poolOut >= minPoolOut (do người gọi xác định) và poolOut <= poolSupply * 0.02 (giới hạn 2% trên mỗi khối trong toàn bộ giao thức). Người tấn công đã sử dụng poolAmountOut = 1 để tránh giới hạn trượt; một giới hạn 2% sẽ buộc họ phải thực hiện 50 lần kết hợp riêng biệt, mỗi lần phải trả phí lệch – khiến cho khoản vay không có lợi nhuận.
4. Bảo mật khả năng kết hợp của cổng atom: bảo vệ chống lặp lại khi có vay flash. Một joinPool có thể được gọi trong một hàm callback vay flash là một vòng lặp định giá. Thêm một dấu hiệu entered tạm thời hoặc kiểm tra mẫu tx.origin == msg.sender? Tốt hơn: làm cho joinPool quay lại nếu block.number đã thấy một vay flash đến người gọi (qua việc phát hiện callback FLASHLOAN_PREMIUM của Aave) hoặc đơn giản là thêm một khoảng thời gian chờ một khối giữa các giao dịch có thể lệch và các kết hợp. Balancer V2 thực hiện điều này với các callback vault.
5. Xử lý fork như các quy trình mới: chạy danh sách kiểm tra fork. Fork BMath không miễn phí. Trước khi chuyển sang mainnet, hãy trả lời câu hỏi: "Các cảnh báo của BMath nào đã bị vô hiệu hóa do thay đổi ý nghĩa của pool từ nơi giao dịch sang chỉ số NAV?" Sau đó, thử kết hợp: cho vay flash + bỏ qua TWAP + đốt cháy khi chuyển giao + điều chỉnh trọng số theo thời gian trong một fork mainnet. Nếu được thử như một kết hợp, thông tin của Sigma Prime sẽ rất quan trọng, không phải là một phát hiện đơn lẻ.
Câu Hỏi Thường Gặp
Số tiền bị đánh cắp trong vụ tấn công Indexed Finance là bao nhiêu? Khoảng 16 triệu đô la – số liệu chính thức của Indexed là 16.042.214 đô la (DEFI5 ~ 6,9 triệu đô la, CC10 ~ 6,1 triệu đô la, NDX/FFA/DEGEN ~ 3 triệu đô la); giá thị trường của PeckShield bằng ETH ~ 3.800 đô la đưa nó lên ~ 16,5 triệu đô la. Con số này phụ thuộc vào chụp ảnh giá ETH/WBTC vào ngày 14 tháng 10 năm 2021. Mức TVL còn lại của giao thức (~ 12 triệu đô la) đã được đội ngũ bảo vệ sau khi tạm dừng hoạt động.
Cách tấn công Indexed Finance hoạt động như thế nào? Tấn công viên đã cho vay ~50 triệu USD để làm biến dạng tạm thời số dư token trong các nhóm cân bằng kiểu Balancer của Indexed. Các nhóm đã định giá các cổ phần LP từ các số dư hiện tại này thông qua BMath.calcPoolOutGivenSingleIn, do đó các số dư biến dạng đã khiến khoản nạp tiền nhỏ trông rất có giá trị và nhóm đã phát hành 40 lần nhiều cổ phần LP hơn. Tấn công viên cũng đã hưởng lợi từ khoảng trống trong việc ghi sổ token giảm giá – nhóm ghi nhận số tiền nạp mà người dùng yêu cầu, không phải số tiền thực sự nhận được sau khi đốt – tăng thêm 3-5% số lượng phát hành. Để đảo ngược biến dạng và đốt cháy LP với giá thực, người ta thu được ~16 triệu USD, tất cả trong một giao dịch nguyên tử cho mỗi nhóm.
Tại sao lại gọi là “manipulation token LP”? Một khoản vay flash là khoản vay không có tài sản thế chấp và phải được trả lại trong cùng một giao dịch. Trong trường hợp manipulation LP, khoản vay không được sử dụng để tài trợ cho hành vi trộm cắp – nó được sử dụng để đặt giá mà nhóm nạn nhân sẽ sử dụng để đánh giá số tiền gửi của kẻ tấn công. Việc vay một khoản vốn lớn, chuyển số dư nội bộ của nạn nhân, gửi số dư nhỏ với giá trị được tăng lên để nhận thêm token LP, sau đó khôi phục số dư và thanh toán LP với giá trị hợp lý, kẻ tấn công sẽ thu được sự khác biệt trong giá trị. Khoản vay được trả từ việc thanh toán với giá trị tăng lên.
Token suy giảm là gì và tại sao nó có ý nghĩa ở đây? Token suy giảm hoặc phí chuyển khoản sẽ tiêu hủy một phần trăm cho mỗi chuyển khoản (ví dụ, 3% của số tiền). Indexed sử dụng _pullUnderlying để ghi nhận amount (được yêu cầu) thay vì balanceAfter - balanceBefore (được nhận), do đó với tỷ lệ tiêu hủy 3%, nó sẽ phát hành LP như thể có 100 token đến khi chỉ có 97 token – một quá trình phát hành quá mức 3%. Ở đây, nó không phải là lợi nhuận chính (sự lệch tâm điểm là 40 lần), nhưng nó đã tăng cường cuộc tấn công lên khoảng 400.000 USD và cho thấy lý do tại sao Yearn và Balancer cảnh báo không bao giờ tin tưởng vào số tiền transferFrom mà không đo lường.
Ai là hacker của Indexed Finance và số tiền đã được thu hồi? Nhà tấn công là một người duy nhất có địa chỉ 0xba5edB19b291cc484cA15514D663Fc331A67A4A, được tài trợ thông qua Tornado Cash. Mặc dù có sự hồi phục của Poly Network, không có số tiền nào được thu hồi – nhà tấn công đã đổi tiền trộm thành WETH và rửa tiền ~1.200 ETH thông qua Tornado Cash trong 100 lô 50 ETH trong vòng 72 giờ. Indexed đã cung cấp một phần thưởng 10% (1,6 triệu USD) nhưng không được chú ý. Người bị hại đã nhận được ~50% thông qua một mã thông báo nợ được hỗ trợ bởi kho bạc và được giao dịch với chiết khấu lớn.
Có thể cuộc tấn công vào tài chính được chỉ mục xảy ra lại không và bạn có cách nào để ngăn chặn nó không? Có — bất kỳ fork của Balancer V1 hoặc pool cân bằng có giá joinPool từ số dư hiện tại mà không có việc ghi sổ thu chi là dễ bị tấn công. Để ngăn chặn, cần có 5 lớp: (1) TWAP/Chainlink oracle cho việc đánh giá LP, không phải là getBalance từ hiện tại; (2) việc ghi sổ số dư thay đổi sau khi thực hiện transferFrom; (3) sự trượt giá minPoolOut + giới hạn tham gia 2% mỗi khối; (4) bảo vệ nhận biết cho vay flash để ngăn chặn việc tham gia trong giao dịch lệch; và (5) danh sách kiểm tra fork để kiểm tra cấu trúc cho vay flash + đốt + cân bằng lại trước khi lên mainnet.
Kết Luận
Hack tài chính được chỉ mục vẫn là ví dụ rõ ràng nhất về việc thao túng mã LP của khoản vay flash – một loại khai thác DeFi trong đó khoản vay không tài trợ cho hành vi trộm cắp mà chỉ ghi lại thông tin của oracle. Các nhóm của Indexed đã đưa ra hai giả định ẩn: số dư thực tế là giá cả hợp lý và số tiền ghi nhận bằng với số tiền nhận được – và gói chúng trong ngôn ngữ quen thuộc của đầu tư chỉ số ("DEFI5, ETF DeFi của bạn"). Một người tham gia duy nhất với 10 ETH và một hợp đồng đã diễn tập cho thấy những giả định đó, kết hợp với sự lệch tâm nguyên tử 50 triệu USD và sự đốt cháy 3%, biến một chỉ số trị giá 16 triệu USD thành một máy ATM. Giải pháp kỹ thuật là rõ ràng: giá so với TWAP, đo lường số tiền nhận được, giới hạn liên kết, và đối xử với các fork như các quy trình mới. Dạy bài học về sản phẩm là phức tạp hơn: khi một chỉ số là AMM của nó, rủi ro không đổi của AMM là rủi ro đầu tư của chỉ số – và người dùng bán lẻ đã mua một ETF chịu rủi ro khai thác cấu trúc thị trường mà họ không bao giờ đồng ý chịu trách nhiệm.
