30 апреля 2022 года злоумышленник использовал ту же уязвимость, что и в инциденте с мостом Nerve Bridge, для атаки на Saddle Finance. Всего под ударом оказалось 4 900 Ether. К счастью, 1 360 Ether из них нам удалось успешно спасти. Подробное описание этого инцидента можно найти в официальном отчете о результатах расследования.


Хотя была использована та же уязвимость, метод атаки отличается от предыдущего. Поскольку новый метод атаки оказался не таким простым, как можно было ожидать, мы считаем, что он заслуживает более глубокого изучения. В этом отчете мы сначала кратко опишем уязвимость, а затем рассмотрим исходный метод атаки, использованный в инциденте с Nerve Bridge. После этого мы сосредоточимся на инциденте с Saddle Finance, проанализировав процесс атаки, чтобы демистифицировать новый метод.
0x1. О развернутых контрактах
Соответствующие адреса контрактов перечислены ниже:
- Целевой контракт MetaSwap: 0x824dcd7b044d60df2e89b1bb888e66d8bcf41491
- Уязвимый контракт MetaSwapUtils: 0x88Cc4aA0dd6Cf126b00C012dDa9f6F4fd9388b17
Стоит отметить, что показанный код контракта MetaSwapUtils, связанный с верифицированным контрактом MetaSwap, НЕ является эквивалентным развернутому контракту MetaSwapUtils, адрес которого указан в Settings, как показано ниже:

Так что не путайте эти два контракта MetaSwapUtils :)
0x2. Анализ уязвимости
Уязвимый контракт относится к MetaPool, который подробно обсуждался в нашем предыдущем блоге. Коротко говоря, MetaPool был первоначально разработан Curve, чтобы позволить объединять отдельную монету со всеми монетами в другом (базовом) пуле, не размывая его ликвидность. По сути, это пул, состоящий из стейблкоина и LP-токена базового пула, который состоит из нескольких других стейблкоинов. Существует проблема с дизайном MetaPool: MetaPool — это в основном пул стейблкоинов, поддерживающий цены на них, в то время как LP-токен базового пула стейблкоинов НЕ является стейблкоином.
На самом деле, цену LP-токена базового пула стейблкоинов можно получить, вызвав функцию getVirtualPrice базового пула, и его цена стабильно растет вместе с накоплением комиссий, взимаемых базовым пулом.
Чтобы справиться с этим, MetaPool увеличивает резерв LP-токена перед расчетом цены, как показано ниже.

Соответственно, если пользователь меняет LP-токен на стейблкоин, количество LP-токена будет масштабироваться перед расчетом цены. И наоборот, если пользователь меняет стейблкоин на LP-токен, рассчитанное количество LP-токена будет уменьшаться перед переводом и бухгалтерским учетом.

Приведенный выше фрагмент кода функции swapUnderlying используется для обмена между стейблкоином в MetaPool и стейблкоинами в базовом пуле. Как показано в двух красных прямоугольниках, функция масштабирует количество входящего LP-токена и уменьшает количество обмениваемого LP-токена.
Однако реализация функции swap не согласуется с реализацией функции swapUnderlying. В частности, первопричиной уязвимости является ошибочный расчет, реализованный в функции swap (а именно в функции _calculateSwap), которая не должным образом масштабирует количество LP-токена. Как показано ниже, слева представлен уязвимый код MetaPool, а справа — исправленная версия.

Злоумышленник, стоящий за инцидентом с Nerve Bridge, использовал несоответствие между функцией swap и функцией swapUnderlying.
(Заметьте, что Nerve Bridge — это форк-проект Saddle Finance.)
После этого Saddle Finance исправила уязвимость и немедленно переразвернула новую версию (V2) библиотеки MetaSwapUtils.
К сожалению, по неизвестной причине, sUSD V2 MetaPool на Ethereum все еще был развернут со старой и уязвимой библиотекой MetaSwapUtils. В результате 30 апреля эта уязвимость была успешно использована злоумышленником еще раз. Интересно, что, в отличие от метода атаки, использованного в инциденте с Nerve Bridge, для атаки на уязвимый MetaPool был применен другой способ.
0x3. Исходный метод атаки в инциденте с Nerve Bridge
Мы повторно используем приведенный ниже рисунок (см. предыдущий блог) для обзора исходного метода атаки.

Поскольку уязвимая функция swap не уменьшает количество обмениваемого LP-токена (Nerve 3-LP), обмениваемая сумма (36 959) на шаге 3 больше обычной.
Затем злоумышленник вызывает функцию swapUnderlying (в которой нет уязвимости), чтобы продать 36 959 Nerve 3-LP (на шагах 4 и 5) за 51 494 fUSDT, что дает прибыль в 1 143 fUSDT.
Разумно объяснить прибыль можно так: злоумышленник получает больше Nerve 3-LP на шаге 3, а затем продает их по «нормальной» цене, используя несоответствие между функцией swap и функцией swapUnderlying.
0x4. Новый метод атаки в инциденте с Saddle Finance
Злоумышленник, совершивший недавний инцидент с Saddle Finance, использовал другой способ атаки на ту же уязвимую функцию swap, не задействуя функцию swapUnderlying.
Здесь мы возьмем одну транзакцию атаки в качестве конкретного примера для иллюстрации процесса.

Интуитивно кажется, что никакой прибыли быть не должно, так как любое следствие шага 3 и шага 4 должно нивелироваться.
В частности, на шаге 3 злоумышленник мог обменять больше saddleUSD из-за отсутствия масштабирования обмениваемого LP-токена (т.е. saddleUSD).
Однако на шаге 4 злоумышленник неизбежно получил бы МЕНЬШЕ sUSD, поскольку уязвимая функция swap не увеличивает количество входящего saddleUSD перед расчетом цены.
Тем не менее, как показано на рисунке выше, злоумышленник получил прибыль в 2 059 771 sUSD через пару свопов на шагах 3 и 4. Чтобы выяснить причину прибыли, мы должны погрузиться в механизм ценообразования и провести глубокое исследование, чтобы понять процесс атаки.
0x4.1 Механизм ценообразования
MetaPool компании Saddle Finance наследует формулу ценообразования Curve:

График функции (когда n равно 2) показан синей кривой на рисунке ниже. (С дизайном формулы можно ознакомиться в официальном документе Curve StableSwap.)

Здесь возникает вопрос: как MetaPool рассчитывает цену для каждого свопа, используя эту формулу?
Допустим, n равно 2, и пользователь использует dx0 токена0 для покупки dx1 токена1. Мы можем симулировать процесс расчета для dx1. В каждом свопе «A» можно рассматривать как константу, а «D» — это единственная переменная, которая может влиять на ценовую кривую. Фактически, «D» увеличивается с накоплением комиссий, взимаемых пулом. В частности, процесс расчета можно свести к следующим трем шагам:
- Шаг I: Подставить текущие резервы пула (x0 и x1) в формулу для расчета текущего
D, который определяет текущую ценовую кривую. - Шаг II: Увеличить x0 на dx0 и подставить текущий
Dи x0 в формулу для расчета нового x1. - Шаг III: Тогда dx1 — это разница между новым x1 и старым x1.
Если токен0 является LP-токеном базового пула, то шаг II становится таким:

Здесь baseVirtualPrice/1e18 во время атаки составляло около 1,0033. И наоборот, если токен является LP-токеном базового пула, то шаг III становится таким:

Чтобы понять, как D влияет на ценовую кривую, мы также используем пример.
Скажем, пользователь сначала меняет dx0 токена0 на dx1 токена1, а затем меняет dx1 токена1 на dx0' токена0.

Как показано на рисунке выше, поскольку на шаге ② взимаются комиссии за первый своп, D увеличивается, чтобы сдвинуть кривую цены вверх (с черной кривой на синюю).
Более того, рисунок четко объясняет причину, по которой dx0' меньше, чем dx0.
0x4.2 Анализ атаки
Чтобы проанализировать причину возникновения прибыли, мы локально развернули уязвимую и исправленную библиотеки MetaSwapUtils и использовали состояние целевого пула в тот момент для симуляции атаки.
Кроме того, во время этой симуляции мы также записали несколько значений, которые могут помочь понять процесс атаки, т. е. A равно 10 000, x_sUSD равно 8 130 463, x_saddleUSD равно 9 688 608, а D равно 17 818 392 в тот момент.

На рисунке выше описан процесс получения прибыли парой свопов:
- Swap-I: обмен 14 800 272 sUSD на 9 657 586 saddleUSD
- Swap-II: обмен 9 657 586 saddleUSD на 16 860 043 sUSD
В частности, Swap-I можно разделить на следующие два шага:
- ①: Обмен 14 800 272 sUSD на 9 625 654 saddleUSD. Теперь
Dувеличивается до 17 931 435 (из-за взимаемых комиссий). - ②: Поскольку уязвимый MetaPool не уменьшает количество обмениваемого saddleUSD, пул теряет 31 932 saddleUSD. Эти потери уменьшают
Dдо 15 736 195, что еще сильнее сдвигает ценовую кривую вниз (с черной кривой на серую).
Аналогично, Swap-II также можно разделить на два шага:
- ③: Поскольку кривая цены сдвинута вниз, те же 9 625 654 saddleUSD могут обменять на 16 891 906 sUSD, что намного больше затрат: 14 800 272 sUSD.
- ④: Поскольку уязвимый MetaPool не масштабирует вверх количество входящего saddleUSD перед расчетом цены, в MetaPool остается 31 863 sUSD, что сдвигает ценовую кривую вверх (с серой кривой на синюю). Тем не менее, пара свопов все равно приносит прибыль в 2 059 771 sUSD.
Очевидно, что приведенный выше анализ ясно объясняет, почему злоумышленник смог получить прибыль, используя новый метод атаки. Кроме того, кажется, что исходный метод атаки был более эффективным, чем новый, из-за sUSD, оставшихся в MetaPool в Swap-II. Конечно, злоумышленник мог проводить множественные атаки, чтобы истощить пул, что и наблюдалось на практике.
0x5. Некоторые выводы
Расследование показывает, что первопричина прибыли в обоих инцидентах одна и та же. В частности, первый своп (своп на LP-токен) уменьшает D уязвимого MetaPool, что в свою очередь сдвигает его кривую цены вниз. Этот сдвиг сильно влияет на последующее ценообразование и является главной причиной последующей прибыли.
О компании BlockSec
BlockSec — это передовая компания в области безопасности блокчейна, основанная в 2021 году группой всемирно известных экспертов по безопасности. Компания стремится повысить безопасность и удобство использования для развивающегося мира Web3, чтобы способствовать его массовому внедрению. Для достижения этой цели BlockSec предоставляет услуги по аудиту безопасности смарт-контрактов и EVM-цепей, платформу Phalcon для разработки безопасности и проактивного блокирования угроз, платформу MetaSleuth для отслеживания и расследования средств, а также расширение MetaDock для эффективного серфинга Web3-разработчиков в криптомире.
На сегодняшний день компания обслужила более 300 уважаемых клиентов, таких как MetaMask, Uniswap Foundation, Compound, Forta и PancakeSwap, и получила десятки миллионов долларов США в двух раундах финансирования от выдающихся инвесторов, включая Matrix Partners, Vitalbridge Capital и Fenbushi Capital.
Официальный сайт: https://blocksec.com/
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



