Взлом Notional Finance на $1,73 млн
04.09.2026 | CoinKyt Company
4 мин
share button
4 сентября 2026 года злоумышленник воспользовался ошибкой в расчёте долга в протоколе Notional Finance и похитил около $1,73 млн из Escrow-контракта. Он создал две долговые позиции, которые при сложении обнулились в системе из-за неправильной обработки чисел. Проверка обеспеченности не заметила долг и разрешила вывод средств.
Расследование «КоинКит» анализирует, как именно сработала атака и куда ушли похищенные активы.

 


Введение


Notional Finance
— это протокол для фиксированного кредитования в DeFi. Пользователи могут давать и брать в долг криптовалюту под заранее известную процентную ставку.

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

fCash
— это внутренние долговые обязательства протокола Notional. Положительная fCash-позиция означает право получить деньги в будущем. Отрицательная — долг, который нужно погасить.

 


Ход инцидента


1️⃣ В старой версии протокола функция перевода fCash-позиций направляла вызов в функцию mintfCashPair(). Эта функция одновременно создавала долговую позицию у одного адреса (payer — заёмщика) и положительную fCash-позицию у другого адреса (receiver — получателя права требования).

2️⃣ После создания позиций контракт проверял только обеспеченность заёмщика. Если у него достаточно залога — операция разрешалась.

3️⃣ Злоумышленник создал для одного и того же заёмщика две отдельные долговые позиции. Сначала — с номиналом 1. Затем — с номиналом 2^128 − 1 (это максимальное число, которое помещается в специальный тип данных).

4️⃣ При проверке обеспеченности система сложила оба долга: 1 + (2^128 − 1) = 2^128.

5️⃣ В коде проверки использовалось преобразование к типу uint128 — это формат хранения чисел, который вмещает только значения от 0 до 2^128 − 1. Когда система попыталась записать число 2^128 в этот формат, произошло сужающее приведение: старший бит отбросился, и вместо огромного долга система увидела ноль.

6️⃣ Проверка обеспеченности посчитала, что у заёмщика нет долга, и пропустила операцию. Сам долг при этом никуда не делся, но система его больше не учитывала.

7️⃣ На адресах-получателях остались крупные положительные fCash-позиции. Злоумышленник использовал их для получения реальных активов из Escrow-контракта. Было выведено 69 242 DAI и 1 658 423 USDC, всего примерно $1,73 млн.

 


Почему это стало возможным


Проблема заключалась в функции _convertToETH(), которая проверяла обеспеченность. В ней использовалось преобразование:
uint128 absBalance = uint128(balance.abs());

Тип uint128 может хранить числа только до 2^128 − 1. Каждый из двух созданных долгов по отдельности помещался в этот предел, поэтому контракт принимал их без проблем. Но после сложения совокупный долг стал равен ровно 2^128.

При сужающем преобразовании в Solidity старшие биты числа отбрасываются. Число 2^128 в двоичном виде — это единица, за которой следует 128 нулей. При отбрасывании старшего бита остаётся 128 нулей — то есть 0.
В результате проверка обеспеченности увидела нулевой долг и разрешила операцию. Возможность создать две отдельные позиции, сложить их до критического значения, а затем небезопасно привести результат к ограниченному формату — и позволила обойти всю систему защиты.

 


Детали расследования: движение средств


Похищенные активы поступили на адрес злоумышленника:
0xDaCC235a494750193695A111D715c2ca12b5Ce38

Оттуда средства в том же виде были переведены на адрес:
0x8aaf01B6F9AcC973274B8718BE4D1C1be10E3be6

Далее оба токена (DAI и USDC) были обменяны на ETH и отправлены на адрес:
0xC95496c917A41a394EfdAC3e0882F5903D24De69

После этого вся сумма в виде ETH была отправлена на Tornado Cash — сервис, который разбивает и смешивает транзакции, чтобы скрыть их источник.

Остаток в размере 0,0112674 ETH был переведён на нелицензированный обменник CCE Cash.

 


Заключение


Инцидент в Notional Finance показал, что математические особенности компьютерных систем — в данном случае ограничения на размер чисел и правила их преобразования — могут стать инструментом для кражи. Создание двух отдельных позиций, которые по отдельности выглядели безопасно, при сложении привели к переполнению формата и обнулению долга. Отсутствие проверки на критическое значение перед преобразованием сделало всю систему обеспеченности бесполезной. Команда «КоинКит» продолжает анализ связанных адресов и методов отмывания средств.