Back to Blog

Анализ инцидента безопасности Popsicle Finance

Code Auditing
August 4, 2021
4 min read

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 выполняет следующие действия:

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

Функции _fee0Earned и _fee1Earned используют одну и ту же логику, а именно реализуют следующую формулу (на примере token0):

user.token0Rewards += PLP.balanceOf(account) * (fee0PerShare - user.token0PerSharePaid) / 1e18

Обратите внимание, что расчет является инкрементальным, что означает: даже если у пользователя НЕТ токенов PLP, рассчитанная награда остается значением, сохраненным в token0Rewards.

Следовательно, мы можем сделать два вывода:

  1. награды пользователя хранятся в token0Rewards и token1Rewards, которые не привязаны ни к одному токену PLP;
  2. функция collectFees зависит только от состояния token0Rewards и token1Rewards, что означает, что награды можно вывести, не владея токенами PLP.

В реальном мире это означает ситуацию, когда клиент вкладывает деньги в банк, а банк выдает ей сертификат на депозит. К сожалению, этот сертификат не защищен от подделки и не привязан к конкретному пользователю. В таком случае можно сделать копии сертификатов и раздать их другим лицам, чтобы получать прибыль от банка.

Ход атаки

Кратко, для осуществления атаки злоумышленник выполнил следующие шаги:

  1. создал три контракта. Один из них использовался для проведения атаки, в то время как два других использовались для вызова функции collectFees и получения наград;
  2. использовал Flash Loan (флэш-кредит), то есть занял большой объем ликвидности у платформы AAVE;
  3. запустил цикл Deposit-Withdraw-CollectFees для выполнения атаки (всего было 8 циклов, и из различных хранилищ Popsicle Finance было выведено большое количество ликвидности);
  4. вернул флэш-кредит обратно в 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

(В алфавитном порядке по фамилии)

https://www.blocksecteam.com

Medium: https://blocksecteam.medium.com/

Twitter: https://twitter.com/BlockSecTeam

Контакт: [email protected]

Ссылки

[1] https://twitter.com/defiprime/status/1422708265423556611

[2] https://tx.blocksecteam.com/

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit