Aztec Connect прекратил работу еще в 2024 году, однако в его смарт-контрактах продолжали храниться пользовательские активы. В июне 2026 года злоумышленник воспользовался архитектурным расхождением между уровнями L1 и L2 и вывел около $2,2 млн всего за одну транзакцию.

Почему даже устаревший смарт-контракт можно ограбить: кейс Aztec Connect на $2,2 млн

17.06.2026

36

14 мин

14 июня 2026 года устаревший смарт-контракт RollupProcessor проекта Aztec Connect (0xff1f2b4adb9df6fc8eafecdcbf96a2b351680455) подвергся атаке. Злоумышленник воспользовался расхождением между параметрами numRealTxs и decoded_slots, что позволило ему вывести активы из пула первого уровня (L1) примерно на $2,2 млн в рамках одной атомарной транзакции.

Хотя Aztec Connect был официально выведен из эксплуатации еще в марте 2024 года, неизменяемый смарт-контракт продолжал хранить пользовательские активы прошлых лет и оставался подвержен рискам. GetBlock AML Research подробно разбирает технические детали атаки с двух точек зрения: анализа исходного кода контракта и данных, записанных непосредственно в блокчейн.

Первопричина уязвимости

Во время обработки результатов работы RollupProcessorV3 возникало структурное несоответствие между диапазоном данных, который проверялся циклом расчетов на уровне L1, и диапазоном данных, который подтверждался через криптографический хеш публичных входных параметров ZK-доказательства.

Злоумышленник воспользовался этим расхождением таким образом, что содержимое 31 из 32 слотов публичных входных данных попадало в корень состояния второго уровня (L2) и подтверждалось ZK-доказательством, но при этом не проходило проверку механизма расчетов на уровне L1.

Decoder.sol: параметр numRealTxs полностью контролировался атакующим Значение numRealTxs считывается из области calldata по смещению 4516 байт и никак не ограничивается проверками непосредственно в блокчейне.

DAO не помогло: как захватили проект TOP и при чем тут Tornado Cash

DAO не помогло: как захватили проект TOP и при чем тут Tornado Cash

История атаки на TOP показывает, что для получения контроля над криптопроектом не всегда нужен взлом. Иногда достаточно приобрести большинство голосов и воспользоваться правилами системы именно так, как они были написаны.

Читать дальше

Параметр decoded_slots округляется до числа, кратного numTxsPerRollup, что необходимо для корректной работы встроенной функции SHA256. Однако именно эта операция округления создает промежуток между numRealTxs и decoded_slots, который злоумышленник может заполнять произвольными данными. RollupProcessorV3.sol: цикл обработки охватывает только numRealTxs слотов

Разрушение модели безопасности

При нормальной работе системы предполагается, что каждый слот публичных входных данных либо проходит проверку на уровне L1-контракта (например, при внесении депозита происходит уменьшение показателя pendingDepositBalance), либо ограничивается правилами ZK-схемы таким образом, чтобы значение publicValue было равно нулю.

Однако в рассматриваемом случае произошло следующее. Функция SHA256 охватывала все 32 слота данных. Фактический размер входных данных составлял 8192 байта, что соответствует 32 слотам по 256 байт каждый. Таким образом, содержимое промежуточных слотов уже было подтверждено криптографическим доказательством.

Одна структура, четыре крупных адреса: что не так со стейблкоинами DAI и USDS

Одна структура, четыре крупных адреса: что не так со стейблкоинами DAI и USDS

Несмотря на оборот свыше 350 миллиардов долларов за 90 дней, большая часть активности USDS связана с внутренними операциями системы. Розничные пользователи, для которых позиционируется накопительный продукт sUSDS, контролируют менее 1% размещенных средств.

Читать дальше

В то же время цикл расчетов на уровне L1 обрабатывал только первый слот. Слоты из диапазона [2..32], находящиеся в образовавшемся промежутке, вообще не проходили проверку со стороны контракта. Ограничение ZK-схемы, согласно которому значение publicValue в этих слотах должно быть равно нулю, либо отсутствовало, либо было обойдено злоумышленником.

Все три уровня защиты зависели друг от друга, но ни один из них по отдельности не обеспечивал безопасность промежуточных слотов. Когда ограничение на стороне ZK-схемы оказалось неэффективным, уровень L1 также не смог обнаружить проблему.

Модель расхождения двух путей обработки

Одни и те же данные calldata использовались двумя разными механизмами, каждый из которых работал со своим верхним пределом обработки.

Механизмы обработки, которые содержали уязвимость

Эти два механизма по-разному определяли, какие именно слоты должны учитываться. Система доказательств ZK воспринимала все 32 слота, тогда как логика L1 фактически обрабатывала только один. Именно это расхождение и стало причиной возможности создавать необеспеченные активы.

Ход атаки

Транзакция злоумышленника содержала в общей сложности 14 вызовов функции processRollup(). Они были разделены на две фазы: сначала семь операций по созданию необеспеченного баланса, затем семь операций по выводу средств. Все было выполнено в рамках одной атомарной транзакции.

Фаза 1. Создание необеспеченного баланса — получение активов на уровне L2 (Rollup #13277–13283)

Сначала внешний адрес злоумышленника 0x0f18d8b44a740272f0be4d08338d2b165b7edd17 вызвал основной контракт 0x06f585f74e0da633ae813a0f23fb9900b61d0fcd, активировав функцию с идентификатором 0x6f3ce701.

После этого основной контракт последовательно перенаправил выполнение в три специальных промежуточных контракта. Каждый из них содержал заранее подготовленные вредоносные наборы данных rollup.

Ключевые параметры этих данных выглядели следующим образом:

  • numRealTxs = 1
  • rollupSize = 1024
  • numInnerRollups = 32

Для первого слота, который был видим для системы L1, использовались параметры:

  • proofId = 0 (пустая операция)
  • publicValue = 0

Для слотов со второго по тридцать второй, которые не были видны логике L1, использовались следующие значения:

  • proofId = 1 (операция депозита)
  • publicValue = N
  • publicOwner = L2-адрес злоумышленника

Все эти данные сопровождались корректно сформированными ZK-доказательствами, при этом схема проверки не ограничивала значение publicValue нулем для промежуточных слотов. Затем первый промежуточный контракт пять раз подряд вызвал функцию RollupProcessor.processRollup() для Rollup №13277–13281.

Проверяющий модуль успешно принимал доказательства, поскольку SHA256-хеш охватывал все 32 слота данных. Однако цикл расчетов на уровне L1 обрабатывал только один слот и видел лишь пустую операцию.

Поддельные депозиты, находившиеся в слотах со второго по тридцать второй, попадали в новый корень дерева Merkle и увеличивали баланс злоумышленника на уровне L2 на величину 5 × 31N. После этого второй промежуточный контракт аналогичным образом обработал Rollup №13282–13283 еще два раза, увеличив баланс злоумышленника еще на 2 × 31N.

В результате на счете злоумышленника во втором уровне оказалось накоплено 7 × 31N необеспеченных средств, тогда как пул активов на первом уровне не потерял ни одного цента.

Десятки кошельков GnosisPay опустошены: детальный разбор дерзкой атаки

Десятки кошельков GnosisPay опустошены: детальный разбор дерзкой атаки

Злоумышленник не взламывал кошельки напрямую — он заставил систему безопасности самостоятельно одобрить мошеннические транзакции. Ошибка в механизме проверки подписей привела к потере около $265 тыс.

Читать дальше

Фаза 2. Вывод средств — превращение искусственно созданного баланса L2 в реальные активы L1 (Rollup #13284–13290)

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

  • В рамках Rollup №13284 были выведены 270 513,054 DAI.
  • В Rollup №13285 злоумышленник получил 167,890 wstETH.
  • В Rollup №13286 было выведено 4 873,857 yvDAI.
  • В Rollup №13287 через третий промежуточный контракт были получены 16,570 yvWETH.
  • В Rollup №13288 были выведены 9 273,734 LUSD.
  • В Rollup №13289 злоумышленник получил 359,047 yvLUSD.
  • Наконец, в Rollup №13290 был произведен финальный вывод 908,987 ETH посредством внутреннего вызова контракта.

Вся атомарная транзакция успешно завершилась с расходом 4 513 539 единиц газа. Поскольку операция выполнялась как единое целое, ее невозможно было частично отменить или откатить.

В результате злоумышленник получил около $2,2 млн, которые были выведены непосредственно из пула пользовательских активов, находившихся под управлением RollupProcessor.

Отслеживание похищенных средств

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

Все активы были переведены из контракта RollupProcessor на внешний адрес злоумышленника 0x0F18D8b44a740272f0be4d08338d2b165b7EdD17 через промежуточный атакующий контракт в рамках одной транзакции.

Схема движения похищенных у Aztec Connect средств. Визуализация: MistTrack

На промежуточном контракте средств не осталось. На момент проведения анализа 100% похищенных активов все еще находились на основном адресе злоумышленника и не демонстрировали признаков дальнейшего перемещения или попыток сокрытия происхождения средств.

Чему можно научиться после этого инцидента

Главный урок этой атаки заключается в том, что в системах ZK-Rollup диапазон данных, который проверяется смарт-контрактом при расчетах, должен полностью совпадать с диапазоном данных, подтверждаемым криптографическим хешем публичных входных параметров.

Если между границей цикла обработки numRealTxs на уровне L1 и диапазоном данных decoded_slots, подтвержденным через SHA256, появляется разрыв, злоумышленник может воспользоваться этим несоответствием. Любые механизмы безопасности, которые рассчитывают исключительно на ограничения внутри ZK-схемы, становятся потенциально уязвимыми.

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

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

Подписывайтесь на Getblock Magazine и будьте всегда в курсе последних новостей из мира криптовалют и цифровой экономики