Пост
Поделитесь своими знаниями.
Рассмотрение эксплойта Протокола Кетуса по иску
22 мая 2025 года была использована крупная уязвимость, направленная против протокола Cetus в блокчейне Sui, в результате чего ущерб составил, по оценкам, 223 миллиона долларов. Из-за необычной механики этот инцидент сразу же привлек внимание всей экосистемы, особенно технических наблюдателей. Ниже представлен всесторонний анализ атаки: от обмена флэш-памятью и манипуляций с галочками до скрытой уязвимости в логике обнаружения переполнения.
https://suiscan.xyz/mainnet/tx/DVMG3B2kocLEnVMDuQzTYRgjwuuFSfciawPvXXheB3x
Настройка
Злоумышленник инициировал эксплойт, используя flash_swap для заимствования большого количества токенов SUI в обмен на HasUI. В отличие от традиционных флэш-займов, flash_swap в Cetus позволяет пользователю получить token1 (в данном случае SUI) авансом, а затем погасить токен0 (hasUI) в рамках той же транзакции. Этот механизм занимает центральное место в настройке злоумышленника.
В данном конкретном случае злоумышленник успешно приобрел 5,76 миллиона SUI и был обязан выплатить 10,02 миллиона HASUI. Но во время этого обмена цена HasUI в пуле ликвидности была сильно изменена. Цена пула была снижена с такта, равного 1,056, до такого низкого значения, что цена составила всего 0,0000009977, что стало огромным падением цены до 0,00009% от первоначальной цены.
Ценовой диапазон, соответствующий диапазону тиков, составляет:
Стратегическое вливание ликвидности
После падения цен злоумышленник использовал open_position для создания позиции ликвидности с узким диапазоном, выбрав строго определенный диапазон тиков (TickLower: 300000, TickUpper: 300200). В этой манипулированной среде они вложили астрономический объем ликвидности: более 10^34 единиц, причем все они находились в сверхсжатом ценовом диапазоне, возникшем в результате обвала тиков.
Это стало возможным благодаря, казалось бы, безобидной функции: get_amount_by_liquidity. В обычных условиях эта функция вычисляет, сколько токенов A и токенов B необходимо для достижения определенного уровня ликвидности. Для этого используются вспомогательные функции, такие как get_delta_a, использующие get_sqrt_price_at_tick.
Однако из-за того, что текущий тик, которым манипулируют, составляет -138185, а выбранный диапазон тиков находится далеко за его пределами (начиная с 300000), логический путь в get_amount_by_liquidity обеспечивал прохождение вычислений через уязвимый участок кода, где была задействована операция сдвига влево (checked_shlw).
Переполнение и усечение: основная уязвимость
Здесь эксплойт становится по-настоящему техническим. Функция checked_shlw должна обрабатывать сдвиг 256-битного числа влево на 64 бита. В средах, подобных Solidity, такая операция рискованна, так как она может переполниться. В этой конкретной реализации была предпринята попытка обнаружить переполнение путем проверки того, превышают ли входные данные заранее заданное пороговое значение: 0xfffffffffffffffffff << 192.
Фактическое пороговое значение для обнаружения безопасного сдвига на 64 бита должно быть равно 2^ (256—64) — 1. Однако значение (0xfffffffffffffffffffff << 192) больше 2^192. Это означает, что тщательно подобранные входные данные могут обойти проверку на переполнение, поскольку они будут ниже порогового значения, используемого в коде, но при этом будут достаточно большими, чтобы вызвать переполнение во время выполнения.
Злоумышленник ввел такие входные данные, в результате чего прирост ликвидности и разницы в цене переполнился бесшумно, в результате чего было получено гораздо меньшее значение, чем предполагалось, — фактически, почти нулевое.
В результате протокол подсчитал, что злоумышленнику достаточно заплатить незначительное количество токенов (по сути, одну единицу), чтобы увеличить объем ликвидности в пуле. Этот просчет позволил злоумышленнику вливать огромные объемы ликвидности без реальных затрат.
Впоследствии злоумышленник удалил добавленную ликвидность с помощью remove_liquidity и завершил атаку, выплатив неоплаченные токены flash_swap через repay_flash_swap. Злоумышленник получил прибыль в размере 5 765 124 SUI и 10 024 321 HASUI. Наконец, команда Cetus устранила уязвимость с помощью двух PR:
https://github.com/CetusProtocol/integer-mate/pull/6/files
Компания Cetus быстро выпустила патч для своего репозитория с целыми числами: первым запросом на перенос была предпринята попытка усовершенствовать функцию обнаружения переполнения. Однако этого первоначального исправления оказалось недостаточно. Использовалась маска размером 1 << 192, которая по-прежнему позволяла пропускать значения в крайних регистрах.
Затем последовал второй запрос на перенос данных, после чего последовало более строгое сравнение: проверялось, что входные данные больше или равны 2^192, что позволило обеспечить надлежащие границы для безопасного смещения влево. Только благодаря этому исправлению уязвимость была эффективно устранена.
- Sui
Основная причина заключалась не в логической ошибке в механике DeFi, а в неспособности правильно определить поведение переполнения при низкоуровневой арифметической операции.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Заработай свою долю из 1000 Sui
Зарабатывай очки репутации и получай награды за помощь в развитии сообщества Sui.

- ... SUIBigSneh+1396
- ... SUISuiLover+1333
- ... SUI0xduckmove+1207
- ... SUIThorfin+1202
- ... SUIOwen+970
- ... SUIharry phan+847
- ... SUItheking+742
- Почему BCS требует точного порядка полей для десериализации, когда структуры Move содержат именованные поля?53
- «Ошибки проверки нескольких источников» в публикациях модуля Sui Move — автоматическое устранение ошибок43
- Сбой транзакции Sui: объекты, зарезервированные для другой транзакции25
- Как ограничения возможностей взаимодействуют с динамическими полями в гетерогенных коллекциях?05