Ramil 🔵 pfp
Ramil 🔵

@ramilmust

Как округлить 1.5 до 1 и потерять 9.57кк$, история взлома zkLend В этом году в ТОП 10 (https://t.me/web3securityresearch/70)уязвимостей в смарт контрактах вошли Arithmetic Errors и Proxy & Upgradability Vulnerabilities. Про атаку на прокси уже был написан пост (https://t.me/web3securityresearch/68), сегодня разберем уязвимость класса арифметической ошибки Что случилось В начале 2025 года был взломан zkLend, развернутый в сети Starknet. В перспективе это привело к закрытию проекта Немного деталей о проекте zkLend позволял давать и брать в долг активы, то есть это набор lending / borrowing операций. После внесения активов пользователю выдавалась обёртка, например wstEth -> zwstEth. Эти zTokens являются nonrebase transferable токенами. То есть количество токенов на кошельке не меняется, но растет их стоимость по мере того, как протокол получает доход. Чтобы вычислять актуальную стоимость активов пользователя используется формула: collateral_balance = lending_accumulator × raw_balance где - collateral_balance - рыночная стоимость активов - raw_balance - количество zTokens пользователя - lending_accumulator - множитель, через который проходит распределение прибыли протокола Еще zkLend позволял брать flash loans. Это краткосрочный займ, который надо вернуть в конце транзакции. Если не вернуть, то транзакция откатывается, если возвращаешь, то надо доплатить комиссию за пользование. Но в версии zkLend был еще и donation механизм. Он позволял отправить вместе с возвратом flash loan некоторую сумму. Эта сумма считывается как доход протокола и обновляет lending_accumulator. Выглядит формула обновления так: new_accumulator = (reserve_balance + totaldebt - amount_to_treasury) / ztoken_supply где - reserve_balance - общая сумма базового токена в контракте - totaldebt - совокупная задолженность всех заемщиков - amount_to_treasury - доля выручки, направляемая в казначейство протокола - ztoken_supply - общее количество выпущенных zTokens В норме ztoken_supply - это большое число, но взлом не является нормой Как проводилась атака 1. Пул wstEth был пуст. Это позволило хакеру сминтить 1 wei zwstEth за 1 wei wstEth, начальное значение аккумулятора стало равно 1 2. Атакующий вызывает flash_loan() функцию, занимает 1 wei, а затем возвращает 1000 wei. 999 wei при этом считываются как donation и отправляются в reserve_balance. Новое значение аккумулятора = 851 3. После повторения этого приема 10 раз значение аккумулятора разгоняется до 4.069 × 10^18. 10 в 18 степени - это уровень точности wstEth 4. Хакер через функцию deposit() вносит в пул 4.069297906051644020 wstETH. Благодаря огромному аккумулятору его raw_balance теперь равен 2 5. Дальше он поочередно совершает deposit и withdraw операции. Эти операции вызывают mint() и burn() Протокол написан на языке Cairo, для деления использовалась библиотека SafeMath с округлением вниз. Как и в Solidity, это означает, что при делении остаток отбрасывается. При выводе средств, протокол должен рассчитать какое количество raw_balance должно быть списано, тут мы возвращаемся к raw_balance= collateral_balance / lending_accumulator Цикл - На ввод отправляется около 8.13859 wstEth (х2 к значению аккумулятора), теперь у хакера raw_balance = 4 - На вывод идет 6.10394 (х1.5 к значению аккумулятора), функция div() из SafeMath делает следующее 1 = 6.10394 / 4.0692, т.к. полтора округляется вниз до единицы - теперь raw_balance = 3, хотя истина должна быть 2.5 Повторяя этот цикл, атакующий разгоняет свой raw_balance до 1724, которые оцениваются в 7000 wstEth 6. Заключительная часть атаки в том, что под это разогнанное значение хакер делает borrow в других пулах на сумму в 9.57кк$ Что можно было сделать? 1. По сути в этом что-то есть от Inflation Attack (https://t.me/web3securityresearch/35), так что помогли бы dead shares (https://t.me/web3securityresearch/37) 2. Округление в пользу протокола 3. Границы для lending_accumulator 4. Границы для изменения lending_accumulator за одну транзакцию 5. Пороги минимумов на ввод/вывод 6. Тесты edge cases 7. Аудит библиотек Материалы, использованные при подготовке поста: - Анализ (https://blog.solidityscan.com/zklend-hack-analysis-e494cb794f71) от SolidityScan - Пост (https://www.halborn.com/blog/post/explained-the-zklend-hack-february-2025) от Halborn - Подробный (https://blocksec.com/blog/zklend-exploit-post-mortem-unraveling-the-details-and-clarifying-misunderstandings-of-the-10m-flash-loan-attack) пост от BlockSec https://t.me/web3securityresearch
0 reply
0 recast
1 reaction