фон

22 августа Balancer официально объявил, что получил серьезные сообщения об уязвимостях, затрагивающих несколько пулов V2 Boost. Пострадало только 1,4% TVL. Несколько пулов были приостановлены, а пользователи были уведомлены о необходимости как можно скорее вывести ликвидность LP. [1] [2]

27 августа система SlowMist MistEye обнаружила атакующую транзакцию, подозревавшуюся в использовании уязвимости Balancer. [3]

Поскольку пул не может быть приостановлен, а некоторые средства по-прежнему затронуты атакой, представители Balancer еще раз напоминают пользователям о необходимости восстановить LP в пострадавшем пуле. [4] Впоследствии Balancer официально опубликовал подробности об уязвимости, раскрытой в августе на Medium [5], и команда безопасности SlowMist рассмотрела их. Подробности следующие:

представлять

Представители Balancer просто указали в своем сообщении, что проблема на этот раз заключается в том, что округление линейного пула вниз и виртуальное предложение составного пула привели к тому, что bptSupply стал равным 0. Для начала давайте кратко рассмотрим содержимое протокола Balancer, связанное с этой уязвимостью.

Балансировщик V2 Хранилище

Протокол Balancer V2 [6] — это децентрализованный протокол автоматического маркет-мейкера (AMM), основанный на Ethereum, который представляет собой гибкий строительный блок для программируемой ликвидности. Его основным компонентом является контракт Vault, который ведет учет всех пулов и управляет учетом и передачей токенов, включая упаковку и распаковку собственного ETH. Другими словами, Vault реализован для отделения учета и управления токенами от логики пула.

В Vault имеется четыре интерфейса, а именно joinPool, exitPool, swap и BatchSwap (присоединение, выход и обмен — это отдельные вызовы, и в одном вызове их комбинация невозможна). Одной из выдающихся функций является пакетный обмен, который может реализовать несколько атомарных обменов между несколькими пулами и соединить выход одного обмена пула со входом другого пула (GiveIn и GiveOut). В системе также реализован Lightning Exchange [7], который аналогичен внутреннему флэш-кредиту.

Линейные бассейны Линейные бассейны

Чтобы повысить эффективность использования капитала LP и решить проблему высоких накладных расходов на деформацию и деформацию, Balancer запустил линейный пул в качестве решения в V2, представив таким образом токен BPT (ERC20 Balancer Pool Token).

Линейный пул [8] содержит основной токен (базовый актив), обернутый токен (обернутый токен) и токен BPT и обменивает активы и их обернутые прибыльные аналоги по известному обменному курсу. Чем выше доля завернутых токенов, тем выше доходность и эффективность использования капитала пула. В процессе деформации обычно используются коэффициенты масштабирования, чтобы гарантировать, что разные токены рассчитываются с одинаковой точностью.

Сборные бассейны Сборные бассейны

Все пулы Balancer представляют собой составные пулы, которые содержат другие токены, а сам пул имеет свои собственные токены. Среди них валюта BPT относится к токену сбалансированного пула ERC20, который является основой всех пулов. Пользователи могут свободно комбинировать токены BPT в других пулах для погашения. Погашение всегда включает в себя пул и два токена: GiveIn и GiveOut. In означает отправку составляющих токенов и получение BPT, а Out означает отправку BPT и получение составляющих токенов. Если бы BPT сам по себе был токеном компонента, его можно было бы обменивать, как и другие токены. Такая реализация представляет собой простой путь пакетного обмена между базовыми активами и токенами во внешнем пуле. Пользователи могут использовать BPT для обмена на базовые активы линейного пула, который также является основой Balancer Boosted Pool [9].

За счет вышеуказанной комбинации формируется комбинируемый пул Balancer. Составной стабильный пул bb-a-USD состоит из трех линейных пулов, при этом простаивающая ликвидность отправляется на внешний протокол (Aave). Например, bb-a-DAI — это линейный пул, содержащий DAI и waDAI (обернутый aDAI). Когда пользователю необходимо выполнить пакетную замену (например, заменить USDT на DAI), пример пути обмена выглядит следующим образом:


1. В линейном пуле USDT обменять USDT на bb-a-USDT (войти в линейный пул USDT);

2. В bb-a-USD bb-a-USDT обменивается на bb-a-DAI (обмен между линейными BPT);

3. В линейном пуле DAI bb-a-DAI обменивается на DAI (выход из линейного пула DAI).

После краткого понимания вышеуказанных необходимых знаний мы входим в ссылку анализа уязвимостей.

анализировать

27 августа группа безопасности SlowMist получила от системы MistEye подтверждение того, что предполагаемая уязвимость Balancer была использована в реальных условиях. Транзакция [3] заключается в следующем:

Злоумышленник сначала предоставил кредит в размере 300 000 долларов США посредством срочного кредита от AAVE. Затем вызывается операция BatchSwap Vault для расчета обмена токенов BPT через комбинируемый стабильный пул bb-a-USD. Наконец, 94 508 USDC обмениваются на 59 964 bb-a-USDC, 68 201 bb-a-DAI и 74 280. бб-а-USDT. Наконец, полученные токены BPT выйдут из пула через контракт exitPool of the Vault в обмен на базовые активы, погасят мгновенный кредит и покинут рынок с прибылью примерно в размере 108 843,7 долларов США.

Видно, что ключ к этой атаке лежит в пакетном обмене, а что именно произошло в пакетном обмене? Давайте посмотрим поближе.

В течение всего процесса пакетного обмена злоумышленник сначала выкупал USDC в пуле bb-a-USDC, а затем обменивал токены BPT, обменивая bb-a-USDC на bb-a-DAI, bb-a-USDT и USDC. Наконец, базовый основной токен USDC обменивается на bb-a-USDT. То есть bb-a-USDC, как ключевой токен BPT, служит токеном компонента GiveOut и GiveIn.

На первом этапе злоумышленник обменивает токены BPT на основные токены USDC в линейном пуле bb-a-USDC с фиксированным коэффициентом масштабирования, а увеличенная сумма фиксируется в bptBalance в пуле. Но после второго обмена onSwap мы обнаружили, что значение sumOut для USDC, обмененных в ходе того же процесса обмена, равно 0. Почему это?


Углубляясь в функцию onSwap, мы обнаруживаем, что в этом процессе сначала будет обработана точность для номинализации и будет рассчитан коэффициент масштабирования соответствующего токена. При следующем вызове функции downscaleDown значение sumOut округляется в меньшую сторону. Если значение между sumOut и scalingFactors[indexOut] сильно различается, вычисленное значение downscaleDown будет равно нулю.

То есть, когда мы используем токены BPT для выкупа основных токенов, если sumOut слишком мал, возвращаемое значение будет округлено до нуля, и это значение меньше 1e12, рассчитанное с помощью scalingFactors. Однако сумма bb-a-USDC, поступающая из sumIn, все равно будет добавлена ​​к виртуальной сумме bptBalance, и эта операция увеличит баланс в пуле bb-a-USDC, что можно расценивать как одностороннее добавление bb. -a-USDC ликвидность.

Затем, используя характеристики комбинируемого стабильного пула, посредством взаимной конвертации между токенами BPT, bb-a-USDC сначала обменивается на другие токены BPT. Чтобы следовать этому процессу обмена, вы можете объединить следующие пути вызова стабильного пула: bb-a-DAI onSwap -> swapGivenIn -> onSwapGivenIn. Сначала замените bb-a-USDC на bb-a-DAI и bb-a-. USDT по порядку. В отличие от онлайн-линейных пулов, составные стабильные пулы требуют обновления кэша обменного курса перед операциями onSwap. Из кода мы видим, что в пуле комбинаций onSwap сначала определяет, нужно ли обновлять курс обмена кэшированных токенов.

После предыдущего обмена количество bb-a-USDC изменилось, и реальная общая сумма после номинализации через _toNominal составляет totalBalance 994 010 000 000, а виртуальный запас токенов BPT составляет 20 000 000 000. Можно подсчитать, что обновленный курс обмена почти в 45 раз превышает исходный курс обмена кэша предыдущего линейного пула, равный 1 100 443 876 587 504 549, что составляет 49 700 500 000 000 000 000.

Впоследствии bb-a-USDC обменивается на USDC в линейном пуле. Однако этот обмен аналогичен второму обмену, который снова приводит к округлению суммы Out до 0, а путь обмена такой же, как и раньше.

Следующий обмен — это обратный обмен USDC на bb-a-USDC, путь обмена — onSwap -> onSwapGivenIn -> _swapGivenMainIn. В ходе этого процесса мы обнаружили, что при расчете суммы Out, которую необходимо выкупить, расчет виртуального предложения основан на разнице между общим количеством выкупленного токена BPT и оставшейся суммой в пуле, которая равна 0.

Это связано с тем, что bptSupply равен 0, а функция _toNominal вызывается непосредственно при расчете BPT Out, и вызов этого пути делает соотношение обмена USDC к bb-a-USDC близким к 1:1.

Подведем итог

BatchSwap соединяет выходные данные обмена одного пула с входными данными другого пула (tokenIn и tokenOut) посредством нескольких атомарных свопов между несколькими пулами и обменивает USDC на токены BPT. При этом пакетном обмене фактической передачи токенов не происходит, но окончательная сумма обмена подтверждается путем записи суммы, переведенной внутрь и наружу. А поскольку обмен линейного пула осуществляется через токен базового актива, метод обмена заключается в расчете ставки с помощью виртуального предложения и фиксированного алгоритма. Таким образом, в пакетном обмене есть две дыры в безопасности:

Первая — это проблема округления в сторону уменьшения линейных пулов. Злоумышленник в одностороннем порядке добавляет в пул основные токены посредством округления, чтобы увеличить долю кэшированных токенов, тем самым манипулируя курсом обмена токенов в соответствующем составном пуле;

Во-вторых, из-за характеристик виртуального предложения объединяемого пула виртуальное предложение рассчитывается путем вычитания баланса в пуле из токена BPT. Если GiveIn является токеном BPT на момент погашения, эта часть будет вычтена из последующего. поставка, злоумышленнику нужно только обменять BPT как GiveIn и сначала манипулировать ее поставкой до 0, а затем выполнить обратную замену, то есть BPT затем используется как GiveOut. В этот момент, поскольку поставка равна 0, алгоритм выполнит это. быть близким к 1: коэффициент 1 ниже, чем коэффициент погашения линейного пула для фактического погашения, что приводит к косвенному манипулированию количеством токенов BPT GiveOut.

Мы можем обнаружить, что первая уязвимость увеличивает обменный курс, а вторая — наоборот снижает обменный курс во время обратного обмена. Злоумышленник воспользовался двойным усилением, чтобы получить прибыль и уйти.

Справочные ссылки:

[1] https://twitter.com/Balancer/status/1694014645378724280

[2] https://forum.balancer.fi/t/vulnerability-found-in-some-pools/5102?u=endymionjkb

[3] https://etherscan.io/tx/0x7020e0ccafff2c86db3df5a2af0cccb4e931fe948f69bf20ea517b0cc99c1f15

[4] https://twitter.com/Balancer/status/1695777503699435751

[5] https://medium.com/balancer-protocol/rate-manipulation-in-balancer-boosted-pools-technical-postmortem-53db4b642492

[6] https://docs.balancer.fi/concepts/overview/basics.html

[7]https://docs.balancer.fi/reference/swaps/flash-swaps.html#flash-swaps

[8]https://docs.balancer.fi/concepts/pools/linear.html

[9]https://docs.balancer.fi/concepts/pools/boosted.html