Cetus Hack

Cetus Hack

brzrbito

Предисловие

22 мая 25 года был взломан ака эксплуатирован DEX протокол Cetus. Казалось бы, рядовая ситуация в криптомире, где каждый месяц, если не каждую неделю, что-то происходит из разряда "опять кого-то нагрели".

Всё нижесказанное является доводами автора и никаких пограничных экспертных мнений не несёт. DYOR.

  1. АММ на мувланге.
  2. Механика нагрева.
  3. Сколько бабок понадобилось "злоумышленнику".
  4. Прецеденты.
  5. Насколько весома вина местного фаундейшена.


АММ на мувланге


ΔA = (L * |√P₁ - √P₀|) / (√P₀ * √P₁) (изменение кол-ва токенов А при изменении цены)

ΔB = L * |√P₁ - √P₀| (изменение кол-ва токенов В при изменении цены)

Где:

ΔA - количество токенов А, которое нужно изъять и внести
ΔB - количество токенов В, которое нужно изъять и внести
L - ликвидность пула
√P₀ - квадратный корень начальной цены
√P₁ - квадратный корень конечной цены
|√P₁ - √P₀| - разница между ценами 

Количество токенов А зависит от, произведения ликвидности пула и абсолютной разницей между ценами (начальной и конечной), деленное на произведение этих же цен.

Пример:

Ликвидность пула (L) = 1000

Начальная цена токена А = 4 (один токена А стоит 4 токена В)

Конечная цена токена В = 9 (теперь один токен А стоит 9 токенов В)

В этом примере мы изымаем А и добавляем В

Сколько нужно вытащить токенов А при изменении цены:

ΔA = (L * |√P₁ - √P₀|) / (√P₀ * √P₁)

(1000 * |√9 - √4|) / (√4 * √9) = (1000 * 1) / 6 = 166.666667 

166.666667 токенов А нужно вытащить из пула так, как цена на него выросла

А сколько нужно добавить токенов В:

ΔB = L * |√P₁ - √P₀|

1000 * |√9 - √4| = 1000 * 1 = 1000

1000 токенов В нужно внести в пул, так как цена на токен А выросла


То есть, чтобы поддержать ликвидность в пуле, нужно 166.666667 токенов А вытащить, а 1000 токенов В добавить.
1 банан стоит 4 яблока, но в какой-то момент 1 банан уже стоит 9 яблок, чтобы поддержать баланс, из под прилавка достают 166.666667 бананов и добавляют 1000 яблок.


Далее, как именно эта формула реализована в move:

#наш токена А, это функция для расчета изменения его кол-ва в пуле

public fun get_delta_a(  
    sqrt_price_0: u128,  #начальная цена
    sqrt_price_1: u128,  #конечная цена
    liquidity: u128,     #ликвидность пула
    round_up: bool       #округление чисел
): u64 {                 #наша дельта токена А в 64 битах


#считаем |√P₁ - √P₀| разницу цен

    let sqrt_price_diff = if (sqrt_price_0 > sqrt_price_1) {
        sqrt_price_0 - sqrt_price_1
    } else {
        sqrt_price_1 - sqrt_price_0
    };

#считаем L * |√P₁ - √P₀| 

    let (numberator, overflowing) = math_u256::checked_shlw(
        full_math_u128::full_mul(liquidity, sqrt_price_diff)
    );

#считаем √P₀ * √P₁

    let denominator = full_math_u128::full_mul(sqrt_price_0, sqrt_price_1);

#считаем (L * |√P₁ - √P₀|) / (√P₀ * √P₁)

    let quotient = math_u256::div_round(numberator, denominator, round_up);

#приводим результат к 64 битному формату

    (quotient as u64)
}



Механика нагрева


С формулами разобрались, далее, каким же образом типочку удалось нагреть логику смарт-контракта.

В конкретном отрывке функции, где мы ищем дельту, которую нужно изъять из пула, есть такая строчка:

(quotient as u64)

Это строчка обрезает результаты до 256 битного формата, чтобы он поместился в 64 битный формат чисел.

Цифры могут быть и вправду большие, но вероятность, что число будет превышать 256 бит очень скромны. Однако, если целенаправленно атаковать этот метод в коде, то как уже понятно, результат на лицо.

Причем это целые числа...


То есть:

Если коробки у прилавка могут содержать только конкретную величину бананов и яблок, то что будет если превзойти эту границу величин, допустим на 1 или 2. Результатом будет то, что бананов изымут гораздо больше, чем должно, если цена на бананы в короткий промежуток времени вырастет по отношению к яблокам. Просто весь прилавок заректит.


То есть:

Если вдруг начальная цена токена А = 100, а конечная цена = 10 миллиардам, то произведение ликвидности к разнице между ценами выйдет за пределы 256 битного формата, которое в свою очередь некорректно округлиться и обрежется до 64 битного формата. А значит, приведение числа в нужный формат будет не верным, допустим оно должно было быть 1234567, а стало 4567890.


Причем, это не хак, это просто эксплойт логики приведенного выше метода по вычислению дельты.


Сколько бабок понадобилось "злоумышленнику"


Ну он же не хакер и не злоумышленник, он просто типок, который взял и сделал. Как говорится "каждый мох".


Однако, каждый ли мох?


Однозначно, типок был не один, как в фильмах про хакеров.

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

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

В-третьих, количественный избыток средств, не 1 мульен, но гораздо больше.


Бабки, люди, инфраструктура - короче, денег на сие мероприятие потребовалось многовато, чем рект моего прилавка.


Стоит уточнить, что пул - CLMM, то есть концентрированный. Экстремально маленький диапазон, буквально пара сот тиков + много бабок + уверенные мощности = 200кк на кармане.


Если есть интерес, то вот его первая транзакция, в которой фигурирует 10кк hasui (тоже sui, но в обертке от стейкинг протокола)

https://suivision.xyz/txblock/DVMG3B2kocLEnVMDuQzTYRgjwuuFSfciawPvXXheB3x



Прецеденты


Вообще, достаточно частый случай манипулирования оракулами в дефае, НО


Но были ведь прецеденты, ведь надо было, как-то это момент утрясти, ведь не один раз аналогичным образом скамились пулы.

Если функция используется в контексте, где результат влияет на передачу токенов, атакующий может использовать флеш займы (аналогично атакам в Ethereum) описанным для манипуляции состоянием пула перед вызовом функции.


Причем, статей на эту тему очень много и все от 6-ти месячной до 2-х годовалой давности.


Об этом писали, это переживали, это хоть как-то исправляли, но увы результат на лицо. Лохи.

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



Насколько весома вина местного фаундейшена


SUI фаундейшен, конечно, канул в моих глазах. Косяк на косяк и сверху ещё косяк. Топ-10 самых популярных методов эксплойта прозевать на самом ровном месте и так бездарно.

Типок то просто использовал метод, а фаундейшен обосрался, как и другие до него. Аналогия с граблями.

Кому и что выплатит фаундейшен, как дальше будет существовать Cetus доколе неясно. Ясно только то, что ещё одному нормальному протоколу вставили палки в колеса.

Да, я въебался на Cetus (на токене), не так много, но всё же, осадочек то есть.




Report Page