Chào mừng bạn trở lại với Spotlight Lỗ Hổng của Sherlock, nơi chúng tôi làm nổi bật một lỗ hổng quan trọng được phát hiện trong một cuộc kiểm toán của Sherlock. Tuần này, chúng tôi xem xét một phép tính mức tài sản thế chấp không chính xác được tìm thấy trong cuộc thi @plaza_finance bởi @0xadrii, @KupiaSecurity, @f, @farman1094_, và @0xnovaman33.
Tóm tắt về lỗ hổng: Trong getRedeemAmount(...), hợp đồng tính toán mức tài sản thế chấp cho việc đổi BOND bằng cách sử dụng trạng thái sau giao dịch: // mã hiện tại (có lỗ hổng) mứcTàiSảnThếChấp = ((tvl - (sốTiềnGửi * GIÁ_MỤC_TIÊU_BOND)) * ĐỘ_CHÍNH_XÁC) / ((cungBOND - sốTiềnGửi) * GIÁ_MỤC_TIÊU_BOND); Bởi vì giá đổi sau đó sử dụng mức tài sản thế chấp ước tính này để quyết định có trả giá tối đa ($100) hay không, một kẻ tấn công có thể mua BOND với các tỷ lệ tạo hỗn hợp (đôi khi được giảm giá) cho đến khi mức tài sản thế chấp (hiện tại) giảm xuống ≤ 1.2, và sau đó đổi tất cả BOND với mức trần $100—tính toán với một sốTiềnGửi được chế tạo để đẩy mức tài sản thế chấp ước tính trở lại trên 1.2. Điều này cho phép kẻ tấn công rút ETH (“chênh lệch không rủi ro”) cho đến khi mức tài sản thế chấp hiện tại của pool đạt đến ngưỡng.
Các bước tấn công: 1) Giai đoạn thiết lập Các tham số ví dụ của pool: - poolReserve = 120 ETH, bondSupply = 3000, levSupply = 200, giá ETH = $3075 Quy tắc định giá: Tạo (mua) BOND: - Nếu collateralLevel ≤ 1.2: creationRate = tvl * 0.8 / bondSupply - Ngược lại: creationRate = $100 Đổi (bán) BOND: - Nếu estimated collateralLevel ≤ 1.2: redeemRate = tvl * 0.8 / bondSupply - Ngược lại: redeemRate = $100
2) Giai đoạn A – Mua BOND với mức giá hỗn hợp/giảm giá - Mua BOND trong khi theo dõi (mức hiện tại) collateralLevel = tvl / (bondSupply * 100). - Lần mua đầu tiên xảy ra khi collateralLevel > 1.2 → đúc gần $100 cho mỗi BOND. - Các lần mua tiếp theo đẩy mức collateralLevel hiện tại xuống dưới 1.2 → đúc với tỷ lệ tạo ra giảm giá (ví dụ, ~$94.07), tích lũy một số lượng lớn BOND với giá rẻ.
3) Giai đoạn B – Đổi tất cả BOND với giá tối đa - Gọi redeem(BOND, depositAmount = attackerBondBalance, ...) - Hợp đồng tính toán mức tài sản thế chấp ước tính bằng cách sử dụng trạng thái sau khi đổi (bondSupply - depositAmount) và (tvl - depositAmount * 100) và (trong ví dụ) nhận được giá trị > 1.2 - Bởi vì giá trị ước tính đó vượt quá ngưỡng, redeemRate được đặt ở mức tối đa $100, cho phép kẻ tấn công rút toàn bộ BOND đã tích lũy với giá $100
4) Hiện thực hóa lợi nhuận - Sự khác biệt giữa các giao dịch mua được chiết khấu và việc bán $100 tạo ra lợi nhuận ròng ETH. - Trong các con số PoC: chi tiêu 60 ETH cho hai giao dịch mua sẽ trả về ~61.89 ETH khi đổi → ~1.89 ETH lợi nhuận. - Kẻ tấn công có thể lặp lại cho đến khi mức tài sản thế chấp của pool hiện tại giảm xuống ~1.2, khai thác khoảng: USD có thể khai thác ≈ ethPrice × poolReserve − 120 × bondSupply
Tác động là gì? Rút tiền trực tiếp / rò rỉ giá trị: Kẻ tấn công đúc với giá chiết khấu và đổi lấy 100 đô la, siphoning ETH từ pool. Không giới hạn cho đến ngưỡng: Có thể tiếp tục cho đến khi mức tài sản thế chấp hiện tại của pool giảm xuống khoảng 1.2. Sự không nhất quán trong định giá hệ thống: Tạo ra cơ hội chênh lệch giá mà người dùng trung thực phải trả bằng cách có dự trữ / kết quả pool tồi tệ hơn.
Nguyên nhân gốc rễ: Sử dụng trạng thái sau giao dịch để định giá việc đổi lại Mã tính toán mức tài sản thế chấp như thể việc đổi lại đã xảy ra: // sử dụng (tvl - depositAmount*100) và (bondSupply - depositAmount) mức tài sản thế chấp = ((tvl - (depositAmount * BOND_TARGET_PRICE)) * PRECISION) / ((bondSupply - depositAmount) * BOND_TARGET_PRICE); 1. Điều này cho phép một kẻ tấn công chọn depositAmount sao cho mức ước tính vượt qua ngưỡng (> 1.2), mở khóa tỷ lệ đổi lại $100, ngay cả khi trạng thái hiện tại của pool không biện minh cho điều đó. 2. Ngưỡng kiểm soát trên một chỉ số bị thao túng Quyết định giới hạn $100 phụ thuộc vào mức tài sản thế chấp ước tính có thể bị thao túng này thay vì mức hiện tại (trước giao dịch), cho phép việc thao túng giá.
Giảm thiểu: Tính toán giá trị đổi thưởng từ trạng thái hiện tại của pool, không phải từ số dư ước tính sau khi đổi thưởng. Giải pháp được đề xuất của dự án là chính xác: - collateralLevel = ((tvl - (depositAmount * BOND_TARGET_PRICE)) * PRECISION) - / ((bondSupply - depositAmount) * BOND_TARGET_PRICE); + collateralLevel = (tvl * PRECISION) / (bondSupply * BOND_TARGET_PRICE);
Củng cố thêm (được khuyến nghị): 1. Tính đơn điệu của giá: Đảm bảo giá đổi không tăng khi depositAmount tăng (không có "bán nhiều hơn, nhận được giá đơn vị tốt hơn"). 2. Định giá dựa trên bất biến: Tạo ra/đổi từ một bất biến duy nhất để sự đối xứng mua/bán ngăn chặn việc chênh lệch một chiều. 3. Kiểm tra trượt giá: Yêu cầu người dùng cung cấp tỷ lệ tối thiểu/tối đa cho cả tạo và đổi. 4. Giới hạn & điều tiết: Giới hạn đổi theo từng giao dịch và theo từng khối để hạn chế thiệt hại nếu các ngưỡng bị tiếp cận. 5. Tính nhất quán giữa các đường đi: Đồng bộ hóa các đường tạo và đổi để sử dụng cùng một định nghĩa mức tài sản thế chấp (chỉ trạng thái hiện tại).
Chúng tôi tự hào đã giúp bảo vệ @plaza_finance thông qua phát hiện này. Khi cần bảo mật tuyệt đối, Sherlock là sự lựa chọn đúng đắn.
3,27K