Технический анализ: у Balancer украли 120 миллионов долларов, в чем была уязвимость?
Ключевая проблема этой атаки заключалась в логике обработки мелких транзакций протоколом.
Оригинальное название: «Анализ уязвимости, приведшей к краже $120M с Balancer»
Источник: ExVul Security
Введение
3 ноября 2025 года протокол Balancer подвергся хакерской атаке на нескольких блокчейнах, включая Arbitrum и Ethereum, что привело к потере активов на сумму 120 миллионов долларов. Основная причина атаки заключалась в двойной уязвимости, связанной с потерей точности и манипуляцией инвариантом (Invariant).
Инфраструктура Chainlink уже долгое время поддерживает самые высокие стандарты в сфере Web3, поэтому X Layer естественным образом выбрал её для предоставления инструментов институционального уровня разработчикам.
Ключевая проблема этой атаки заключалась в логике обработки протоколом мелких транзакций. Когда пользователь совершает обмен на небольшую сумму, протокол вызывает функцию _upscaleArray, которая использует mulDown для округления чисел вниз. Если баланс и сумма ввода одновременно находятся на определённой границе округления (например, в диапазоне 8-9 wei), возникает значительная относительная ошибка точности.
Ошибка точности передаётся в процесс вычисления инварианта D, что приводит к аномальному уменьшению значения D. Изменение D напрямую снижает цену BPT (Balancer Pool Token) в протоколе Balancer. Хакер воспользовался этим заниженным курсом BPT, чтобы провести арбитраж по заранее спланированному маршруту транзакций, что в итоге привело к огромным финансовым потерям.
Эксплуатация уязвимости Tx:
Перемещение активов Tx:
Технический анализ
Точка входа атаки
Точкой входа для атаки стал контракт Balancer: Vault, а именно функция batchSwap, которая внутри вызывает onSwap для обмена токенов.

Из параметров и ограничений функции можно сделать несколько выводов:
1. Атакующий должен вызвать эту функцию через Vault, прямой вызов невозможен.
2. Внутри функции вызывается _scalingFactors() для получения коэффициентов масштабирования.
3. Операции масштабирования сосредоточены в _swapGivenIn или _swapGivenOut.
Анализ модели атаки
Механизм расчёта цены BPT
В модели стабильного пула Balancer цена BPT является важным ориентиром, определяющим, сколько BPT получит пользователь и сколько активов приходится на каждый BPT.

В расчётах обмена в пуле:

Часть, служащая базой для цены BPT, — это инвариант D, то есть для манипуляции ценой BPT необходимо управлять D. Далее рассмотрим процесс вычисления D:

В приведённом выше коде вычисление D зависит от массива balances после масштабирования. То есть требуется операция, изменяющая точность этих balances, чтобы привести к ошибке в расчёте D.
Корень потери точности

Операция масштабирования:

Как показано выше, при вызове _upscaleArray, если баланс очень мал (например, 8-9 wei), округление вниз через mulDown приводит к значительной потере точности.
Подробное описание процесса атаки
Этап 1: Подгонка к границе округления

Этап 2: Провоцирование потери точности (основная уязвимость)

Этап 3: Получение прибыли за счёт заниженной цены BPT

Как показано выше, атакующий с помощью Batch Swap совершает несколько обменов в одной транзакции:
1. Первый обмен: BPT → cbETH (корректировка баланса)
2. Второй обмен: wstETH (8) → cbETH (провоцирование потери точности)
3. Третий обмен: базовый актив → BPT (получение прибыли)
Все эти обмены происходят в рамках одной batch swap транзакции, используя общее состояние баланса, однако при каждом обмене вызывается _upscaleArray для изменения массива balances.
Отсутствие механизма Callback
Основной процесс инициируется Vault. Как же накапливается потеря точности? Ответ — в механизме передачи массива balances.

Анализируя приведённый выше код, видно, что хотя при каждом вызове onSwap Vault создаёт новый массив currentBalances, в Batch Swap:
1. После первого обмена баланс обновляется (но из-за потери точности обновлённое значение может быть неточным)
2. Второй обмен рассчитывается на основе результата первого
3. Потеря точности накапливается, в итоге инвариант D значительно уменьшается
Ключевая проблема:

Заключение
Атака на Balancer произошла по следующим причинам:
1. Использование округления вниз в функции масштабирования: _upscaleArray использует mulDown для масштабирования, что при малых балансах (например, 8-9 wei) приводит к значительной относительной потере точности.
2. Чувствительность расчёта инварианта к точности: вычисление инварианта D зависит от массива balances после масштабирования, и потеря точности напрямую влияет на уменьшение D.
3. Отсутствие проверки изменений инварианта: в процессе обмена не проверяется, находится ли изменение инварианта D в допустимых пределах, что позволяет атакующему многократно использовать потерю точности для занижения цены BPT.
4. Накопление потери точности в Batch Swap: в рамках одной batch swap транзакции потери точности от нескольких обменов накапливаются, что в итоге приводит к огромным финансовым потерям.
Эти две проблемы — потеря точности и отсутствие проверки — в сочетании с тщательно продуманными граничными условиями со стороны атакующего привели к этим потерям.
Дисклеймер: содержание этой статьи отражает исключительно мнение автора и не представляет платформу в каком-либо качестве. Данная статья не должна являться ориентиром при принятии инвестиционных решений.
Вам также может понравиться
Миф о 100% победе разрушен: почему киты утонули в этом цунами?

Планы Уолл-стрит: что можно купить на 500 миллионов долларов в Ripple?

Свайпать, чтобы делать ставки? Как Warden с помощью режима Tinder переворачивает рынок прогнозов


