Автор: Цзюцзю, Конг и Лиза

фон

По данным службы безопасности SlowMist, 23 ноября 2023 года была атакована децентрализованная торговая платформа KyberSwap, в результате чего злоумышленник получил прибыль в размере около 54,7 млн ​​долларов США. Команда безопасности SlowMist немедленно вмешалась в анализ и поделилась следующими результатами:

первопричина

Благодаря кривой реинвестирования (функция кривой реинвестирования) KyberSwap Elastic, когда базовая ликвидность и ликвидность реинвестирования участвуют в расчете как фактическая ликвидность, пул использует функцию CalcReachAmount для расчета количества токенов, необходимых для обмена на границе шкалы. что больше ожидаемого. , в результате чего следующая цена sqrtP превышает sqrtP граничной шкалы, а пул использует знак неравенства для проверки sqrtP, в результате чего протокол не обновляет ликвидность через _updateLiquidityAndCrossTick, как ожидалось.

необходимые знания

Прежде чем начать анализ, нам необходимо знать некоторые ключевые знания о KyberSwap, чтобы понять содержание этого анализа.

KyberSwap — это децентрализованная торговая платформа с новой моделью оптимизации ликвидности — KyberSwap Elastic. Механизм централизованного маркет-мейкера ликвидности, принятый в этой модели, позволяет LP распределять ликвидность по индивидуальным ценовым диапазонам и вводит кривую реинвестирования, которая автоматически объединяет комиссии LP за неактивную ликвидность в пуле.

Во-первых, что такое централизованный маркет-мейкер ликвидности (CLMM)? Как и в случае с Uniswap v3, поставщики ликвидности могут размещать свои средства для обеспечения ликвидности в пределах настраиваемого ценового диапазона, и их ликвидность будет использоваться только тогда, когда цена попадает в этот диапазон. Uniswap v3 (https://blog.uniswap.org/uniswap-v3) и KyberSwap (https://docs.kyberswap.com/liquidity-solutions/kyberswap-elastic) предоставляют подробную документацию для объяснения, мы здесь. Простой Иллюстрация пула ETH/USDC иллюстрирует то, что вам нужно знать, чтобы прочитать эту статью:

Источник: Концепция эластичной ликвидности KyberSwap (https://docs.kyberswap.com/liquidity-solutions/kyberswap-elastic/concepts/concentrated-liquidity#liquidity-tracking-lp-contributions-at-a-specified-price)

Выше представлен пул ETH/USDC с тремя одинаковыми позициями ликвидности и текущей ценой 1995 года. В CLMM ценовые диапазоны называются тиковыми диапазонами. Тиковый диапазон ликвидности Позиции 1 — 1960-2020, тиковый диапазон ликвидности Позиции 2 — 1980-2000, тиковый диапазон ликвидности Позиции 3 — 1990-2000.

Из рисунка видно, что текущий диапазон — это диапазон с лучшей ликвидностью, а ликвидность трех позиций перекрывается на тике 1990-2000 годов. Когда цена ETH упадет до 1985, ее цена выйдет за пределы диапазона тика 1990. В это время она выйдет из диапазона ликвидности позиции 3, но все еще находится в пределах диапазона ликвидности позиций 1 и 2, поэтому новый Ликвидность в пределах диапазона исключает ликвидность позиции 3. Когда цена ETH поднимется до 2005 года, его цена переместится вправо за пределы диапазона тика 2000. В это время ликвидность позиций 2 и 3 будет исключена, но она все равно будет находиться в диапазоне позиции 1. То есть, когда цена пересечет границу ликвидности, ликвидность обновится, либо увеличится, либо уменьшится.

В отличие от Uniswap v3, KyberSwap Elastic инновационно представляет новую функцию — кривую реинвестирования. Это дополнительный пул AMM, в котором накапливаются комиссии, взимаемые пользователями, осуществляющими погашение в пуле, с кривой, поддерживающей диапазон цен от 0 до бесконечности. Объединяя кривую реинвестирования с исходной кривой цен (то есть кривые разделены, но средства по-прежнему находятся в одном пуле), KyberSwap Elastic позволяет комиссионным LP накапливаться и своевременно получать доход, когда цена превышает диапазон. своей позиции.

Кратко разобравшись с механизмом KyberSwap Elastic, мы проанализируем этапы атаки.

Анализ шагов атаки

В качестве примера для анализа мы возьмем атакующую транзакцию 0x485...0f3:

1. Злоумышленник сначала одолжил 2000 WETH у AAVE и обменял 6,8496 WETH на frxETH в пуле KyberSwap, в результате чего цена frxETH превысила все позиции поставщика ликвидности. В это время текущее значение цены sqrtP (представленное умножением текущей цены на квадратный корень из 2^96) увеличивается до 20282409603651670423947251286016, расположенного на тике 110909.

2. Далее злоумышленник добавил 0,006948 frxETH и 0,1078 WETH в качестве ликвидности в указанном ценовом диапазоне [110909, 111310], затем удалил часть ликвидности и, наконец, контролировал значение ликвидности в этом ценовом диапазоне на уровне 74692747583654757908, чтобы ликвидность соответствовала. сумма, необходимая для последующих расчетов атаки. В это время ликвидность в интервале тика [110909,111310] есть только у злоумышленника, а значение цены sqrtP тика 111310 составляет 20693058119558072255662180724088.

3. Затем злоумышленник обменял 387,17 WETH на 0,005789 frxETH по текущему курсу 110909. Эта крупная биржа подняла текущее значение цены sqrtP до 20693058119558072255665971001964, превысив sqrtP на граничной шкале 111310.

4. Наконец, злоумышленник использовал 0,005868 frxETH для обратного обмена 396,2 WETH с sqrtP, что немного превышает шкалу цен 111310. После обмена цена упала обратно в диапазон шкалы [110909,111310]. В это время злоумышленник получил прибыль, а его обратная биржа обменяла примерно на 9 WETH больше, чем форвардная биржа.

Почему такой простой и незатейливый метод атаки может обменять больше средств, чем ожидалось? Это тесно связано с кривой реинвестирования KyberSwap Elastic. Далее мы раскроем его метод получения прибыли посредством детального анализа.

Анализ принципа атаки

Благодаря вышеуказанным шагам мы знаем, что на последнем этапе обратного обмена было обменено больше средств, чем ожидалось. Текущий sqrtP на момент обмена был 20693058119558072255665971001964, что больше, чем цена TicketUpper 111310, когда злоумышленник добавил ликвидность. тиковый график. Укажите его местоположение.

Поскольку он превышает диапазон шкалы ликвидности [110909, 111310], добавленной злоумышленником, текущее местоположение sqrtP теоретически не имеет ликвидности. Он может получить эффективную ликвидность только путем пересечения шкалы 111310 влево во время процесса обмена. и мы проверим, погашается ли он так, как ожидалось.

Как показано на рисунке ниже, когда мы смотрим на ликвидность в текущем масштабе sqrtP, мы обнаруживаем, что без учета кривой реинвестирования должно быть большое количество ликвидности в диапазоне, где ликвидность должна быть равна 0, и это намного больше, чем ожидалось. Реинвестируйте ликвидность кривой, и сумма ликвидности соответствует шкале [110909,111310].

Это делает так, что при обмене действительный обмен токенов произойдет на тике 111310, как показано на изображении ниже.

После действительного обмена на тике 111310 sqrtP переместит этот тик в диапазон [110909,111310], чтобы выкупить оставшиеся токены. Просматривая предварительные знания, мы знаем, что ликвидность будет обновляться при пересечении диапазона позиции ликвидности. В KyberSwap Elastic Pool ликвидность в диапазоне [110909, 111310] будет добавлена ​​к кривой через функцию _updateLiquidityAndCrossTick для участия в обмене токенов. , следующим образом Как показано на рисунке.

Это приведет к тому, что эффективная ликвидность внутри шкалы [110909, 111310] будет добавлена ​​к избыточной ложной ликвидности справа от шкалы 111310, в результате чего общая эффективная ликвидность при обмене внутри шкалы [110909, 111310] будет намного больше, чем Ожидалось, что, как показано на графике ниже, эффективная ликвидность удвоилась, чем ожидалось.

А поскольку повышенная ликвидность в текущем диапазоне тиков делает пул глубже, чем ожидалось, злоумышленник может получить больше средств, чем ожидалось. Эти дополнительные средства поступают из ликвидности в других диапазонах тиков в пуле.

И почему на правой стороне шкалы 111310 неожиданно больше ликвидности, а количество ликвидности такое же, как и ликвидность в диапазоне [110909,111310]? Единственное объяснение может заключаться только в том, что пул не выполнил операцию обновления ликвидности, как ожидалось, во время предыдущего процесса обмена. Как показано на рисунке ниже, теоретически, когда предыдущий обмен пересекает тик 111310, функция _updateLiquidityAndCrossTick также должна вызываться для обновления ликвидности после того, как sqrtP войдет в правую часть тика 111310.

На самом деле мы анализируем этот процесс обмена. При выполнении обмена Пул рассчитает фактическую сумму, использованную для обмена, а также комиссию за обмен и новое значение цены sqrtP с помощью функции ComputeSwapStep. Теоретически при пересечении диапазона ликвидности результатом расчета sqrtP будет sqrtP, попадающий на тик 111310 на границе диапазона. Но на самом деле новый sqrtP превысил sqrtP масштаба 111310. Как показано на рисунке ниже, sqrtP масштаба 111310 равен 20693058119558072255662180724088, но фактический sqrtP равен 20693058119558072255665971001964.

Поскольку новый sqrtP не попадает на sqrtP в граничном масштабе 111310, то есть swapData.sqrtP != swapData.nextSqrtP, это заставит пул думать, что текущий sqrtP все еще находится в диапазоне [110909, 111310] , поэтому операция проверки ликвидности будет пропущена. Функция _updateLiquidityAndCrossTick не будет запускаться для обновлений ликвидности!

Но почему же новый nextSqrtP не попадает на границу? Анализируя расчет CalcReachAmount, мы видим, что сумма, выкупленная в результате атаки, 387170294533119999999, ровно меньше суммы ликвидности в текущем диапазоне 387170294533120000000.

Это приводит к тому, что nextSqrtP не присваивается значение targetSqrtP, а остается равным 0, поэтому оно будет напрямую передано через функцию CalcFinalPrice для окончательного расчета sqrtP, что делает результат его расчета больше, чем sqrtP тика 111310.

Таким образом, функция CalcReachAmount является ключевой, она используется для расчета количества токенов, необходимых при обмене с currentSqrtP на targetSqrtP. Анализируя формулу его расчета, мы можем узнать, что результат его расчета в основном зависит от текущей ликвидности L, которая представляет собой сумму базовой ликвидности и реинвестиционной ликвидности.

Мы все знаем, что в Uniswap v3 нет функции кривой реинвестирования, не потому ли, что добавление ликвидности реинвестирования приводит к тому, что результат расчета CalcReachAmount оказывается больше, чем ожидалось?

В результате тестирования, без учета ликвидности реинвестирования, результат расчета CalcReachAmount составляет 387160697969657129472, что меньше суммы, обмененной в результате атаки, swapQty 387170294533119999999.

sqrtP, рассчитанный с помощью методаcomputeSwapStep без учета ликвидности реинвестирования, попадает точно в масштаб 111310:

Итак, правда выходит наружу благодаря функции KyberSwap Elastic «Кривая реинвестирования», при использовании базовой ликвидности и ликвидности реинвестирования для расчета обмена от текущего sqrtP до границы шкалы sqrtP, количество необходимых токенов будет больше, чем ожидалось. в результате преобразованный sqrtP превышает sqrtP границы шкалы, заставляя протокол полагать, что ликвидность в текущем диапазоне шкалы соответствует требованиям обмена, а затем останавливает операцию обновления ликвидности для масштабов, пересекающих границу.

Анализ туманного трека

Эксплойт KyberSwap 1: 0x50275e0b7261559ce1644014d4b78d4aa63be836

KyberSwap Exploiter 2: 0xc9b826bad20872eb29f9b1d8af4befe8460b50c6

KyberSwap Exploiter 3: 0xae7e16cAa7a4d572FfF09924Bf077a89485850Cb

KyberSwap Exploiter 4: 0xd01896e3D4F130Ffd6f6a5A9d6780bbd7008d71d

Согласно анализу MistTrack, злоумышленники KyberSwap получили в общей сложности более $54,7 млн ​​прибыли, используя сети Ethereum, BSC, Arbitrum, Optimism, Polygon, BASE, Scroll и Avalanche.

На Ethereum KyberSwap Exploiter 1 изначально финансировался за счет 20 ETH, переведенных из Tornado Cash. Среди них 0,1 ETH было переведено в KyberSwap Exploiter 2, 2 ETH было переведено в FixFloat, а 6,5 ETH было перекрёстно привязано к цепочкам Arbitrum, Optimism, Scroll и Base соответственно. KyberSwap Exploiter 2 получил прибыль в размере более 7,58 миллионов долларов США от токенов, включая USDC, WETH, KNC и т. д., которые еще не были переведены.

На BSC KyberSwap Exploiter 1 получил 4,2678 BNB, переведенных из FixFloat, в качестве остатка, который еще не был переведен.

На Arbitrum KyberSwap Exploiter 2 заработал токенов на сумму более 20,29 миллионов долларов, включая WBTC, WETH, ARB, DAI и т. д., из которых 500 WETH были переведены на 0x98d69d3ea5f7e03098400a5bedfbe49f2b0b88d3. Этот адрес перевел 300 WETH в Ethereum. еще не было переведен. Примечательно, что KyberSwap Exploiter 2 перевел 1000 WETH на адрес Indexed Finance Exploiter 0x84e66f86c28502c0fc8613e1d9cbbed806f7adb4.

На Optimism KyberSwap Exploiter 2 заработал более 15,64 миллиона долларов в токенах, включая wstETH, WETH, OP, DAI и т. д., которые еще не были переданы.

На Polygon первоначальные средства KyberSwap Exploiter 1 поступили из 2 666,1243 MATIC, переведенных фиксированным Float, а затем 100 MATIC были переведены в KyberSwap Exploiter 2. Текущий баланс Exploiter 1 составляет 2 564,0016 MATIC, а KyberSwap Exploiter 2 заработал более 2,93 миллиона долларов США; в токенах, включая WBTC, WETH, DAI и т. д., которые еще не были переведены, KyberSwap Exploiter 3 получил прибыль в размере более 5,75 млн долларов США в токенах, включая wstETH, USDT, USDC и т. д., и перевел большую часть токенов; по адресу 0xa4c92d7482066878bb1e2c0510f42b20d79a7ea9.

На BASE KyberSwap Exploiter 2 заработал более $1,95 млн в токенах, включая USDC, WETH и т. д., которые еще не были переведены.

На Avalanche первоначальные средства KyberSwap Exploiter 1 поступили от 49 AVAX, переведенных из FixFloat, тогда как KyberSwap Exploiter 2 получил прибыль в размере более 23 500 долларов США в токенах, включая 293,0756 WAVAX, 17 316,0305 USDC, которые еще не были переведены; получил прибыль в размере более 565 000 долларов США. Токен USD, включая WAVAX, USDC и т. д., и перевел USDC на адрес 0x9296fa3246f478e32b05d4dde35176d927be703f.

Команда безопасности SlowMist заблокировала соответствующие адреса, и большая часть средств еще не переведена. Мы продолжим следить за изменениями средств.

в заключение

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

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

ссылка

Адрес злоумышленника: 0x50275e0b7261559ce1644014d4b78d4aa63be836.

Контракт атаки: 0xaf2acf3d4ab78e4c702256d214a3189a874cdc13

Связанные транзакции атаки:

0x485e08dc2b6a4b3aadcb89c3d18a37666dc7d9424961a2091d6b3696792f0f3

0x09a3a12d58b0bb80e33e3fb8e282728551dc430c65d1e520fe0009ec519d75e8

0x396a83df7361519416a6dc960d394e689dd0f158095cbc6a6c387640716f5475