4 августа 2021 года проект Popsicle Finance понес огромные финансовые потери (более 20 млн долларов) в результате атаки [1].
После ручного анализа мы подтверждаем, что это была атака типа double-claiming («двойное получение»), то есть лазейка в системе вознаграждений позволила злоумышленнику многократно запрашивать награды.
Ниже мы на примере транзакции атаки проиллюстрируем процесс атаки и основную причину уязвимости.
Предыстория
Popsicle Finance — это платформа для оптимизации доходности, поддерживающая множество хранилищ (vaults) для различных сетей (например, Ethereum и BSC).
В частности, пользователь сначала вызывает функцию deposit для предоставления ликвидности и получает токен ликвидности Popsicle (сокращенно PLP). После этого Popsicle Finance управляет ликвидностью пользователя (взаимодействуя с такими платформами, как Uniswap) для получения прибыли.
Пользователь может вызвать функцию withdraw, чтобы забрать ликвидность из Popsicle Finance, которая рассчитывает сумму на основе токенов PLP.
Стимулирующее вознаграждение поступает от ликвидности и накапливается с течением времени.
Пользователь может вызвать функцию collectFees для получения наград, которая и является ключевым звеном этой атаки.
Анализ уязвимости
В функции collectFees для пользователя рассчитываются token0Reward и token1Reward (награды за соответствующие пары LP-токенов). Вся логика расчета проста. Однако функция использует модификатор updateVault, который применяется для соответствующего обновления наград.


Кратко говоря, updateVault выполняет следующие действия:
- сначала вызывает функцию
_earnFeesдля получения накопленной комиссии из пула; - затем вызывает функцию
_tokenPerShareдля обновленияtoken0PerShareStoredиtoken1PerShareStored, которые представляют собой количество токенов token0 и token1 в пуле на каждую долю; - наконец, вызывает функции
_fee0Earnedи_fee1Earnedдля обновления наград пользователя (т.е.token0Rewardsиtoken1Rewardsсоответственно).

Функции _fee0Earned и _fee1Earned используют одну и ту же логику, а именно реализуют следующую формулу (на примере token0):
user.token0Rewards += PLP.balanceOf(account) * (fee0PerShare - user.token0PerSharePaid) / 1e18
Обратите внимание, что расчет является инкрементальным, что означает: даже если у пользователя НЕТ токенов PLP, рассчитанная награда остается значением, сохраненным в token0Rewards.
Следовательно, мы можем сделать два вывода:
- награды пользователя хранятся в
token0Rewardsиtoken1Rewards, которые не привязаны ни к одному токену PLP; - функция
collectFeesзависит только от состоянияtoken0Rewardsиtoken1Rewards, что означает, что награды можно вывести, не владея токенами PLP.
В реальном мире это означает ситуацию, когда клиент вкладывает деньги в банк, а банк выдает ей сертификат на депозит. К сожалению, этот сертификат не защищен от подделки и не привязан к конкретному пользователю. В таком случае можно сделать копии сертификатов и раздать их другим лицам, чтобы получать прибыль от банка.
Ход атаки
Кратко, для осуществления атаки злоумышленник выполнил следующие шаги:
- создал три контракта. Один из них использовался для проведения атаки, в то время как два других использовались для вызова функции
collectFeesи получения наград; - использовал Flash Loan (флэш-кредит), то есть занял большой объем ликвидности у платформы AAVE;
- запустил цикл Deposit-Withdraw-CollectFees для выполнения атаки (всего было 8 циклов, и из различных хранилищ Popsicle Finance было выведено большое количество ликвидности);
- вернул флэш-кредит обратно в AAVE и отмыл прибыль через Tornado.Cash.

В частности, цикл Deposit-Withdraw-CollectFees состоит из нескольких шагов, которые можно легко пометить и четко резюмировать с помощью нашего онлайн-инструмента [2]:

Анализ прибыли
В общей сложности злоумышленник получил от Popsicle Finance 20 млн долларов, включая 2.56 тыс. WETH, 96.2 WBTC, 160 тыс. DAI, 5.39 млн USDC, 4.98 млн USDT и 10.5 тыс. UNI. После этого эксплойта злоумышленник сначала обменял все остальные токены на ETH через Uniswap и WETH, а затем отмыл деньги с помощью Tornado.Cash.
Авторы
Юфэн Ху, Зилинг Лин, Джунджи Фей, Лей Ву, Яджин Чжоу @BlockSec
(В алфавитном порядке по фамилии)
Medium: https://blocksecteam.medium.com/
Twitter: https://twitter.com/BlockSecTeam
Контакт: [email protected]
Ссылки
[1] https://twitter.com/defiprime/status/1422708265423556611



