Back to Blog

Потеряно ~11,3 млн $: Multicall Router, Nostra | BlockSec Weekly

Code Auditing
24 сентября 2026 г.
10 min read
Key Insights
  • Этот отчёт охватывает 2 инцидента безопасности на общую сумму примерно $11.3M убытков, затрагивающих Ethereum и Starknet. Обе цифры являются оценками на момент инцидента, и Nostra Finance заявила, что её окончательные потери и объём возмещённых средств пока неизвестны.

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

  • Ни один из инцидентов не потребовал наличия дефекта в широко известном протоколе. Уязвимости находились в пользовательском интеграционном коде, привязанном к устоявшимся строительным блокам, — в одном случае это был стек модулей Safe, а в другом — конфигурация оракул-адаптера.

За прошедшую неделю (2026/09/14 - 2026/09/20) мы зафиксировали 2 инцидента безопасности с общим предполагаемым ущербом около $11,3 млн.

Дата Инцидент Тип Предполагаемый ущерб
2026/09/15 Unknown Multicall Router Ненадлежащий контроль доступа ~$7,8 млн
2026/09/17 Nostra Finance Некорректная конфигурация оракула ~$3,5 млн

Бесплатное сканирование безопасности

Быстрая проверка безопасности с помощью нашей собственной автоматизированной системы анализа.

Сканировать бесплатно

Главное событие недели: Unknown Multicall Router

Этот инцидент был выбран, потому что незаметное изменение идентификатора вызывающей стороны в цепочке вложенных вызовов маршрутизатора обошло механизм авторизации в кошельке Safe, использующем пользовательские модули, что позволило вывести значительный объём активов.

15 сентября 2026 года MEV-бот, действующий под именем Yoink, опередил (front-run) попытку эксплойта, направленного против кошелька Safe, который управлял своими активами через пользовательские модули стратегий, что привело к предполагаемому ущербу примерно в $7,8 млн [1]. Запросы поступали в эти модули через маршрутизатор multicall, где ошибка авторизации при вложенных вызовах позволила недоверенным инструкциям попасть в цепочку модулей, а повторно используемое разрешение дополнительно обеспечило неавторизованную операцию.

Предпосылки

Кошелёк Safe может подключить модуль Safe. После подключения модуль может вызывать execTransactionFromModule(), чтобы дать кошельку команду выполнить операции без мультиподписного одобрения, поэтому подключённый модуль представляет собой постоянную привилегию в отношении активов кошелька. Пострадавший кошелёк Safe подключил два компонента стратегии: модуль Gateway и модуль LP.

Модуль Gateway определял многократно используемые шаблоны команд, каждый из которых описывал операцию, разрешённую пострадавшему кошельку Safe, а конкретные значения подставлялись во время выполнения. Он принимал команды только от вызывающих сторон из собственного списка авторизованных вызывающих. Каждое выполнение также должно было сопровождаться доказательством Меркла, проверяемым по сохранённому корню, которое подтверждало подлинность вызываемого шаблона команды. Некоторые шаблоны предписывали кошельку вызывать модуль LP, который выполнял операции с ликвидностью Uniswap v4, используя активы кошелька. Таким образом, управление возвращалось через сам кошелёк, а не передавалось напрямую от одного модуля к другому:

Authorized Caller
       |
       v
Gateway module -- verify(command, Merkle proof, root)
       |
       | execTransactionFromModule(...)
       v
Safe wallet context
       |
       v
   LP module --> mintPosition(...)

Операторы в этом инциденте не вызывали модуль Gateway напрямую. Запросы поступали через маршрутизатор multicall, который отправлял пакетные вызовы от их имени. Поскольку маршрутизатор был непосредственным вызывающим при пересылке легитимного запроса, список авторизованных вызывающих модуля Gateway включал сам маршрутизатор.

Через этот путь пострадавший кошелёк Safe мог вносить aEthrsETH, токен-расписку Aave за предоставленный rsETH, в пул Uniswap v4, минтя NFT позиции обратно на кошелёк. Любой держатель aEthrsETH мог сжечь его через Aave, чтобы вывести базовый rsETH.

Пострадавший кошелёк Safe также занимал средства под это обеспечение в Aave. Поэтому Aave отслеживала для него коэффициент здоровья (health factor) — отношение стоимости обеспечения к долгу — и отклоняла перевод обеспечения, который оставил бы этот коэффициент ниже 1.

Анализ уязвимости

Маршрутизатор по адресу 0x4f00...8ebC не верифицирован в исходном коде. Поэтому следующее описание основано на его развёрнутом байткоде, декомпилированной логике, трассировках транзакций и публичной реконструкции путём форк-теста, а не на авторитетных именах уровня исходного кода.

Логика диспетчеризации маршрутизатора принимала цель, которая либо находилась в его белом списке, либо являлась адресом самого маршрутизатора, а затем проверяла список авторизованных вызывающих этой цели по msg.sender текущего вызова. Ничто не сохраняло идентификатор исходного внешнего вызывающего при вызове, который маршрутизатор совершал по отношению к самому себе.

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

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

Анализ атаки

Ранее выданное доказательство Меркла для того же шаблона команды оставалось пригодным для использования с другими значениями времени выполнения. Само по себе это свойство не обходило проверку авторизации вызывающего в Gateway, но обеспечивало пригодное разрешение после того, как вложенный маршрут через маршрутизатор прошёл эту проверку авторизации.

Следующий анализ основан на транзакции 0x0e7680...a8705.

Перед успешной транзакцией первоначальный атакующий развернул атакующий контракт, контролируемый атакующим токен PAT, а также второй контракт, который впоследствии выполнял обмен PAT.

В следующем блоке атакующий вызвал prepare(), чтобы создать и инициализировать пул Uniswap v4 PAT/aEthrsETH.

MEV-бот Yoink обнаружил готовящийся эксплойт и опередил первоначального атакующего, вызвав подготовленный атакующий контракт. Полученный вызов поступил в маршрутизатор, заставил маршрутизатор вызвать самого себя, а затем достиг модуля Gateway с маршрутизатором в качестве msg.sender. Будучи подключённым модулем, Gateway затем мог заставить пострадавший кошелёк Safe выполнить переданную операцию без мультиподписного одобрения.

Инструкция заставила пострадавший кошелёк Safe предоставить примерно 2900 aEthrsETH в качестве ликвидности в контролируемый атакующим пул PAT/aEthrsETH, в диапазоне тиков [10, 20]. Транзакция также минтила соответствующий NFT позиции Uniswap v4 на кошелёк, из-за чего операция выглядела в рамках ожидаемого потока ликвидности. Это не забрало весь баланс aEthrsETH кошелька: сумма была ограничена так, чтобы проверка коэффициента здоровья Aave всё ещё проходила, оставляя кошелёк с коэффициентом здоровья 1.001182484056805114.

Затем атакующий контракт обменял контролируемый атакующим PAT почти на весь внесённый aEthrsETH через этот второй контракт. Он сжёг полученные токены-расписки через Aave и вывел соответствующее количество rsETH. Из примерно 2900 rsETH, поступивших боту Yoink, примерно 2882,37 rsETH ушли получателю прибыли, в то время как примерно 17,63 rsETH были обменены на ETH, и почти весь полученный ETH был выплачен строителю блока.

Заключение

Первопричиной стал дефект авторизации в пользовательской инфраструктуре, подключённой к одному кошельку Safe, усугублённый разрешением, которое не привязывало все параметры выполнения. Это не следует относить на счёт основных контрактов Safe, Aave, Uniswap v4 или Kelp.

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

Начните работу с Phalcon Explorer

Погрузитесь в транзакции, чтобы действовать разумно

Попробовать бесплатно

Другие инциденты этой недели

Nostra Finance

17 сентября 2026 года денежный рынок Nostra на Starknet был подвергнут эксплойту через завышенную цену оракула NSTR, что позволило занять активы на сумму примерно $3,5 млн под переоценённое обеспечение. Первопричиной стала конфигурация интеграции оракула, которая принимала слишком мало источников ценообразования, позволив манипулируемой котировке из неглубокого пула существенно повлиять на агрегированную цену. Nostra приостановила свои рынки [2], а Pragma сообщила, что адрес атакующего был заморожен и работа по возврату средств продолжается [3]. Итоговый ущерб и возможности возврата средств остаются неизвестными.

Предпосылки

Nostra управляла денежным рынком на Starknet, где пользователи могли предоставлять поддерживаемое обеспечение и занимать другие активы в соответствии со стоимостью обеспечения, определённой оракулом.

Nostra получала цены NSTR через собственный контракт price-feed, который делегировал запросы основному контракту оракула, читающему данные из Pragma — оракула, публикующего агрегированные цены в Starknet. Издатели передавали наблюдения в Pragma под именованными источниками, включая AVNU и GECKOTERMINAL, и задокументированная конфигурация NSTR описывала медиану по трём из них [4][5]. Каждый ответ оракула включал цену, десятичную точность, временную метку и количество вносящих вклад источников [6]. Основной контракт оракула хранил MinAggregatedSources — настраиваемое минимальное количество вносящих вклад источников.

Развёрнутая реализация агрегации не была прочитана напрямую. Тем не менее два независимых признака указывают в одном направлении: открытый исходный код Pragma возвращает среднее двух средних значений при чётном количестве записей [6], а ответ MEDIAN, наблюдавшийся в этом инциденте, был равен арифметическому среднему двух его вносящих вклад наблюдений.

Цифры, стоящие за этими источниками, брались из рынка. Наблюдение GECKOTERMINAL могло быть получено из ончейн-пулов, и одной из таких площадок в Starknet является Ekubo — децентрализованная биржа, использующая концентрированную ликвидность, аналогично Uniswap v3. Поставщики ликвидности размещают активы в выбранных диапазонах тиков, а свопы перемещают цену пула через активные диапазоны, при этом промежутки без активной ликвидности могут разделять позиции, размещённые по существенно разным ценам.

Nostra использовала цену NSTR, полученную через этот путь оракула, для оценки внесённого обеспечения и расчёта заёмной способности аккаунта.

Анализ уязвимости

Денежный рынок Nostra считывал цены NSTR из контракта 0x6838...5bf0, который её документация указывает как price feed для NSTR [7]. Этот контракт делегировал запросы основному оракулу, который он определял, — 0x7b05...f0ab, где MinAggregatedSources был настроен на 1. Pragma рекомендует использовать не менее трёх источников ценообразования и сообщила после инцидента, что принудительный минимум в три источника отклонил бы принятый в данном случае ответ [3].

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

Это была слабость конфигурации интеграции, а не ошибка масштабирования десятичных значений или реализации медианы. Pragma не обнаружила дефекта ни в одном из расчётов [3]. Недостаточный порог источников позволил корректно рассчитанному результату на основе недостаточно диверсифицированного набора входных данных определять стоимость обеспечения и заёмную способность.

Анализ атаки

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

Следующий анализ основан на транзакции 0x2460fd...cdf00e.

Сначала атакующий создал пул Ekubo NSTR/SolvBTC и внёс 1,5 SolvBTC в качестве односторонней ликвидности в нижнем, неактивном ценовом диапазоне. Затем атакующий добавил примерно 1900 NSTR и 0,0001514751 SolvBTC в районе нормальной рыночной цены и выполнил несколько свопов в этом пуле.

Далее атакующий разместил 190 NSTR в виде односторонней ликвидности в узком диапазоне, значительно превышающем нормальную цену. Убрав ликвидность в районе нормальной рыночной цены, атакующий оставил пустой промежуток без ликвидности перед этой высокоценовой позицией.

Своп, содержащий всего 0,00000001 SolvBTC, пересёк пустой диапазон и переместил пул к тику -6645400, на границу высокоценовой позиции. Манипулированная стоимость пула впоследствии была передана как наблюдение GECKOTERMINAL для NSTR/USD в размере $99,02439975.

Второе наблюдение, вносящее вклад, переданное под источником AVNU, оценивало NSTR в $0,00596118. В этом ответе отсутствует наблюдение от третьего настроенного источника, оставляя эти два значения единственными, дошедшими до агрегации [4].

При наличии двух значений ответ MEDIAN представлял собой их арифметическое среднее — примерно $49,51518046 за NSTR. Nostra приняла полученную оценку и рассматривала внесённый атакующим депозит NSTR как достаточное обеспечение для существенного займа.

При первом выявленном изъятии средств атакующий использовал отдельный аккаунт, удерживающий обеспечение в NSTR, чтобы занять примерно 939,386010 ETH по завышенной оценке [4]. Nostra сообщила, что полная последовательность заимствования также включала STRK, USDC, USDT, WBTC и DAIv1, с совокупной заёмной стоимостью примерно $3,5 млн [2].

Заключение

Инцидент стал результатом недостаточного порога источников оракула в интеграции Nostra, а не ошибки в обработке десятичных значений или расчёте агрегации Pragma. Ответ с двумя источниками оставался действительным, даже несмотря на то, что одно наблюдение поступило из легко манипулируемого пула.

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

Начните работу с Phalcon Security

Обнаруживайте каждую угрозу, оповещайте о том, что важно, и блокируйте атаки.

Попробовать бесплатно

Источники

[1] https://x.com/Phalcon_xyz/status/2099741447776096270

[2] https://x.com/nostrafinance/status/2100577538053493076

[3] https://www.pragma.build/updates/nostra-nstr-incident

[4] https://x.com/Phalcon_xyz/status/2100818035082952751

[5] https://www.pragma.build/asset/NSTR-USD?network=mainnet

[6] https://github.com/Astraly-Labs/pragma-oracle

[7] https://docs.nostra.finance/lend-and-borrow/deployed-contracts/money-market-mainnet

О компании BlockSec

BlockSec — это универсальный поставщик решений в области блокчейн-безопасности и криптовалютного комплаенса. Мы создаём продукты и услуги, помогающие клиентам проводить аудит кода (включая смарт-контракты, блокчейн и кошельки), пресекать атаки в реальном времени, анализировать инциденты, отслеживать незаконные средства и выполнять обязательства по AML/CFT на протяжении всего жизненного цикла протоколов и платформ.

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

Лучший аудитор безопасности для Web3

Проверьте дизайн, код и бизнес-логику перед запуском

Sign up for the latest updates
Потеряно ~320 млн $: взломы Liquid Network и Symbiosis | BlockSec
Security Insights

Потеряно ~320 млн $: взломы Liquid Network и Symbiosis | BlockSec

Отчёт за 2026/09/07–2026/09/13: два инцидента, ~$320М убытков. Эксплойт Liquid Network (кэш rangeproof без разделителей полей) дал 4000 незалогового L-BTC. На Bitcoin-маршруте Symbiosis отрицательная комиссия позволила выпустить триллионы syBTC — убыток ~9.97 BTC (~$770K).

Потеряно ~9,4 млн $: эксплойты Injective и Aquifer | BlockSec Weekly
Security Insights

Потеряно ~9,4 млн $: эксплойты Injective и Aquifer | BlockSec Weekly

За неделю (31.08–06.09.2026) четыре инцидента безопасности принесли убытки ~$9.4М в Injective, Solana, Ethereum и Flow EVM: Injective (~$4.8М), Aquifer (~$2.47М), Notional Finance V1 (~$1.73М), Ankr FLOW (~$410K).

За пределами смарт-контракта: операционная безопасность доменов и DNS в Web3
Security Insights

За пределами смарт-контракта: операционная безопасность доменов и DNS в Web3

Аудит контрактов не проверяет сам контракт. Мы провели 800 SEAL-проверок DNS и регистраторов для 100 доменов из TVL Top 100 DefiLlama — лишь один домен прошёл все. Каких четырёх мер защиты не хватает большинству и почему это критично для пользователя.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit