25 января 2026 года мы зафиксировали серию подозрительных транзакций, направленных на контракты жертв, развернутые SwapNet и Aperture Finance в сетях Ethereum, Arbitrum, Base и BSC, с общим ущербом более 17 миллионов долларов. Если говорить в общих чертах, первопричина обоих инцидентов довольно проста и уже была изложена в наших первоначальных оповещениях [1, 2]: контракты жертв открывают возможность произвольного вызова (arbitrary-call) из-за недостаточной проверки входных данных, что позволяет злоумышленникам злоупотреблять существующими одобрениями токенов (token approvals) и вызывать transferFrom для вывода активов.
Тем не менее, оба набора контрактов жертв являются закрытыми, и при декомпиляции они превращаются в тысячи строк кода с глубоко вложенной и сложной логикой ветвления, что значительно затрудняет анализ. Более того, последующие пост-мортемы (отчеты об инцидентах), выпущенные затронутыми проектами [3, 4], в основном фокусировались на исправлении ситуации и восстановлении, а не на обсуждении технических деталей. В результате ряд важных вопросов остался без ответа, включая то, как были сконструированы уязвимые пути вызова и почему существующие проверки не смогли предотвратить эксплуатацию.
В этом отчете мы представляем более подробный технический анализ, основанный на декомпилированном байт-коде и трассировках выполнения в цепочке (on-chain). Хотя отсутствие исходного кода ограничивает видимость, анализа на уровне байт-кода оказывается достаточно для восстановления уязвимой логики. Он выявляет несколько интересных наблюдений о дизайне контрактов, которые не были очевидны сразу из общих оповещений.
Мы начнем с глубокого анализа инцидента со SwapNet, а затем подробно рассмотрим инцидент с Aperture Finance.
Инцидент со SwapNet
Предыстория
SwapNet [5] — это агрегатор DEX, разработанный для поиска оптимальных маршрутов обмена путем агрегирования ликвидности из нескольких источников в сети, включая AMM и частных маркет-мейкеров. Протокол также позволяет пользователям указывать пользовательские маршрутизаторы или пулы при выполнении обменов, предлагая дополнительную гибкость.
Анализ первопричины
Этот инцидент возник из-за недостаточной проверки входных данных, предоставляемых пользователем, что позволяет злоумышленнику инициировать вызовы transferFrom() с произвольными параметрами. В результате активы, которые ранее были одобрены для контрактов жертв (например, 0x616000e384Ef1C2B52f5f3A88D57a3B64F23757e), могли быть переведены злоумышленнику.
Судя по декомпилированному байт-коду, функции 0x87395540() не хватает надлежащей проверки критических входных данных. Заменяя ожидаемый адрес маршрутизатора или пула на адрес токена (например, USDC), контракт ошибочно воспринимает токен как допустимую цель выполнения. Это приводит к выполнению низкоуровневого вызова с данными (calldata), контролируемыми злоумышленником.
Следовательно, контракт жертвы выполняет вызовы вида: approvedAsset.transferFrom(victim, attacker, amount), что позволяет злоумышленнику вывести все одобренные активы.
Ход атаки
Было замечено несколько атак на SwapNet. В качестве примера мы используем транзакцию в сети Base 0xc15df1d131e98d24aa0f107a67e33e66cf2ea27903338cc437a3665b6404dd57.
Злоумышленник просто вызвал функцию 0x87395540() контракта жертвы с вредоносными входными данными. Этот вызов состоит из двух основных этапов.
- Ключевая внутренняя переменная (например,
v51) была установлена на USDC, обходя предполагаемую логику маршрутизации.
- Был выполнен низкоуровневый вызов с использованием данных, контролируемых злоумышленником, что привело к вызову
USDC.transferFrom()и выводу всех одобренных средств в USDC.
Сводка потерь, транзакций и затронутых контрактов
Инцидент со SwapNet привел к оценочным убыткам в ~13,41 млн долларов в нескольких сетях. В таблицах ниже приведены сводные данные по основным транзакциям эксплойта и затронутым адресам контрактов жертв.
Инцидент с Aperture Finance
Предыстория
Aperture Finance [6] — это DeFi-протокол, который управляет позициями концентрированной ликвидности, такими как Uniswap V3 LP, от имени пользователей. Его закрытые контракты (например, 0xD83d960deBEC397fB149b51F8F37DD3B5CFA8913) позволяют пользователям создавать позиции Uniswap V3 и управлять ими с использованием нативных токенов.
Предполагаемый рабочий процесс для создания позиций UniswapV3
При создании позиций Uniswap V3 через функцию 0x67b34120() контракт выполняет предполагаемый трехэтапный рабочий процесс:
-
Оборачивание (wrapping) нативных токенов.
-
Обмен нативных токенов через внутреннюю функцию
0x1d33(). -
Создание позиций UniswapV3.
Проблема возникает на этапе 2: 0x1d33() выполняет кастомизированный обмен через низкоуровневый вызов, где критические параметры (например, цель вызова и данные вызова) по-видимому контролируются пользователем и недостаточно проверяются, что позволяет совершать непредусмотренные внешние вызовы. Более подробная информация представлена в следующих разделах.
Анализ первопричины
Как и в случае со SwapNet, инцидент в Aperture Finance вызван недостаточной проверкой входных данных при низкоуровневых вызовах. Когда вызывается 0x67b34120(), внутренняя функция 0x1d33() выполняет низкоуровневый вызов, используя данные, предоставленные пользователем, без наложения строгих ограничений на цель вызова или селектор функции.
Как показано на рисунке ниже, данные вызова, используемые для инициирования низкоуровневого вызова, полностью основаны на входных данных злоумышленника.
Это позволяет злоумышленникам формировать вредоносные данные вызова, которые приводят к выполнению approvedToken.transferFrom(victim, attacker, amount) в контексте контракта жертвы. В результате могут быть выведены не только токены ERC20, но и одобренные NFT позиций Uniswap V3.
Ход атаки
Было замечено несколько атак на Aperture Finance. В этом разделе мы используем транзакцию в Ethereum 0x8f28a7f604f1b3890c2275eec54cd7deb40935183a856074c0a06e4b5f72f25a в качестве репрезентативного примера.
-
Злоумышленник создал контракт для атаки
0x5c92884dFE0795db5ee095E68414d6aaBf398130. -
Контракт для атаки вызвал функцию
0x67b34120()с вредоносными входными данными и100wei ETH (т.е.msg.value==100).
- a) Нативный ETH был обернут в WETH через функцию
WETH.deposit().
- b) Была вызвана внутренняя функция
0x1d33()для выполнения низкоуровневого вызова. На этом этапе в контексте контракта жертвы был вызванWBTC.transferFrom(victim, attacker, amount), что позволило злоумышленнику перехватить одобренные токены. Стоит отметить, что проверка баланса в конце функции0x1d33()была пройдена. В частности, функция0x1d33()сравнивала изменения баланса с выходным значением обмена (т.е.varg2.word2), также указанным злоумышленником. В результате вызовы были успешно выполнены, при этом не было получено ничего лишнего.
- Наконец, была вызвана функция
NonfungiblePositionManager.mint()для создания позиции для злоумышленника с использованием100weiWETH.
Интересные находки
Сравнивая нормальные и аномальные транзакции по созданию позиций, мы заметили, что в обоих случаях токены были одобрены для одного и того же получателя (например, OKX DEX: TokenApprove), но были указаны разные адреса маршрутизатора (т.е. DexRouter и WBTC). Это позволяет предположить, что контракт может обеспечивать проверку того, кто именно получил одобрение на использование токенов, но при этом не проверять фактическую цель выполнения, оставляя критическую брешь, доступную для эксплуатации через произвольные вызовы.
Нормальная транзакция: https://app.blocksec.com/phalcon/explorer/tx/eth/0xc823b703c716fa9078e1d71714b734557bd540ddd1e41590dd73da7c5aba0200
Аномальная транзакция: https://app.blocksec.com/phalcon/explorer/tx/eth/0x8f28a7f604f1b3890c2275eec54cd7deb40935183a856074c0a06e4b5f72f25a
Сводка потерь, транзакций и затронутых контрактов
Инцидент с Aperture Finance привел к совокупным убыткам в размере около 3,67 млн долларов в нескольких сетях. В таблицах ниже сведены основные транзакции эксплойта и соответствующие адреса контрактов жертв.
Заключение
Хотя инциденты со SwapNet и Aperture Finance затронули разные протоколы и сети, основной вопрос в обоих случаях несложен: контролируемые пользователем низкоуровневые вызовы в сочетании с недостаточной проверкой входных данных в контрактах, удерживающих одобрения токенов. Эти инциденты служат напоминанием о том, что гибкость в дизайне контрактов должна тщательно сбалансироваться строгими ограничениями на вызовы, особенно в системах с закрытым исходным кодом, где внешний аудит ограничен.
Ссылки
[1] https://x.com/Phalcon_xyz/status/2015614087443697738
[2] https://x.com/Phalcon_xyz/status/2015624519898234997
[3] https://meta.matcha.xyz/SwapNet-Incident-Post-Mortem
[4] https://x.com/ApertureFinance/status/2015938720453820752
[6] https://x.com/ApertureFinance
О компании BlockSec
BlockSec — поставщик комплексных решений в области безопасности блокчейнов и крипто-комплаенса. Мы создаем продукты и услуги, которые помогают клиентам проводить аудит кода (включая смарт-контракты, блокчейн и кошельки), перехватывать атаки в режиме реального времени, анализировать инциденты, отслеживать незаконные средства и соблюдать требования AML/CFT на протяжении всего жизненного цикла протоколов и платформ.
BlockSec опубликовала множество статей по безопасности блокчейнов на престижных конференциях, сообщила о нескольких атаках «нулевого дня» на DeFi-приложения, заблокировала множество хакерских атак, спасая более 20 миллионов долларов, и обеспечила безопасность криптовалют на миллиарды долларов.
-
Официальный сайт: https://blocksec.com/
-
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



