Back to Blog

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

Code Auditing
17 сентября 2026 г.
13 min read
Key Insights
  • Этот отчёт охватывает 2 инцидента безопасности на общую сумму приблизительно $320M убытков в сети Liquid Network, биткоин-сайдчейне, и Symbiosis, биткоин-мосте, развёрнутом в BNB Smart Chain, Ethereum и Rootstock. Эксплойт Liquid Network составил более 99% от общей суммы, а на Symbiosis пришлось приблизительно $770K.

  • В обоих случаях проверка, которая должна была остановить подделку, выполнялась и сообщала об успехе, подтверждая при этом неверные данные. Нода Liquid возвращала true для rangeproof, который она никогда не проверяла, потому что вердикт для другого доказательства был записан под тем же ключом кэша. Подписанты Symbiosis создали действительную подпись для суммы минтинга, которую их собственный декодер на стороне Bitcoin вычислил из полей, контролируемых вкладчиком.

  • Ценность поддельного баланса зависит от способа его вывода, а не от номинальной стоимости. Почти все 4 000 необеспеченных L-BTC в Liquid ушли через двустороннюю привязку (two-way peg) в виде настоящих биткоинов, переместив ~$320M; syBTC, отчеканенный Symbiosis, превысил предложение биткоина более чем в две тысячи раз, но пулы, через которые его нужно было продавать, содержали 11,26 syBTC, и убыток для поставщиков ликвидности и пользователей составил приблизительно 9,97 BTC.

За прошедшую неделю (2026/09/07 - 2026/09/13) мы зафиксировали 2 инцидента безопасности с общим оценочным ущербом около $320M.

Дата Инцидент Тип Оценочный ущерб
2026/09/06 * Liquid Network Некорректное построение ключа кэша ~$320M
2026/09/11 Symbiosis Некорректная проверка офчейн-депозита ~$770K

*Инцидент Liquid Network произошёл 6 сентября и не был освещён в отчёте за прошлую неделю. Он включён сюда для полноты картины.

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

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

Главное событие недели: Liquid Network

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

6 сентября 2026 года Liquid Network, сайдчейн Bitcoin, подвергся эксплойту на сумму около $320M [1]. Коллизия в кэше проверки rangeproof в Elements, программном обеспечении узла, на котором работает Liquid, позволила вердикту valid, зафиксированному для одного выхода, быть возвращённым для второго, совершенно другого выхода, доказательство которого, таким образом, было принято без какой-либо проверки. Злоумышленник использовал это для создания 4000 L-BTC, не обеспеченных биткоином, а затем вывел их через обычный механизм peg-out сети. На следующий день 3400 BTC были возвращены федерации, оставив у злоумышленника около 598.5 BTC [2].

Предыстория

Liquid Network — это сайдчейн Bitcoin, построенный на Elements, платформе блокчейна с открытым исходным кодом, производной от кодовой базы Bitcoin. Он существует для того, чтобы перемещать биткоин быстрее, дешевле и приватнее, чем позволяет основная цепь. Биткоин пересекает границу между двумя сетями через двустороннюю привязку (peg): при peg-in пользователь блокирует BTC у федерации сети — фиксированной группы проверенных организаций, совместно хранящих средства привязки — и получает эквивалентное количество L-BTC; при peg-out пользователь уничтожает L-BTC, а федерация высвобождает соответствующий BTC. Блоки Liquid не майнятся. Ротируемый набор функциональных узлов федерации предлагает их, а порог подписей федерации финализирует их.

Как и Bitcoin, Liquid отслеживает средства как непотраченные выходы транзакций (UTXO), а не как балансы счетов. Транзакция называет существующие непотраченные выходы, разблокирует их и создаёт новые, причём создаваемая ценность должна равняться потребляемой. Каждый выход несёт скрипт блокировки — scriptPubKey. Выход, скрипт которого начинается с OP_RETURN, никогда не может быть потрачен; он существует для передачи данных, и peg-out выражается именно таким типом выхода.

Liquid также по умолчанию скрывает суммы. Вместо того чтобы записывать цифру в выход, он записывает обязательство Педерсена (Pedersen commitment) для этой цифры. Обязательства аддитивны, поэтому узел может подтвердить, что входы и выходы транзакции сбалансированы, не узнав ни одного из задействованных значений. Это свойство работает в обе стороны: обязательство может точно так же скрывать значение, ведущее себя как отрицательное, что позволило бы выходам транзакции превысить входы и всё равно оставаться сбалансированными. Поэтому каждый выход, сумма которого скрыта, несёт rangeproof — доказательство того, что зафиксированная сумма лежит в диапазоне [0, 2^64). Проверка rangeproof затратна, а один и тот же выход проверяется более одного раза — когда транзакция попадает в мемпул, и снова когда она приходит в блоке — поэтому Elements ведёт кэш уже принятых доказательств, ключом для которого служат само доказательство и данные, по которым оно проверялось.

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

Дефект заключается в том, как Elements — программное обеспечение узла, которое запускает каждый участник Liquid — кэширует уже проверенные rangeproof.

CachingRangeProofChecker::VerifyRangeProof() вычисляет запись кэша для находящегося перед ним выхода и, в случае совпадения, немедленно возвращает успех, не трогая само доказательство:

Эта запись формируется функцией ComputeEntryRangeProof(), которая последовательно записывает четыре поля в единый поток SHA-256 и финализирует дайджест:

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

Ни одно из четырёх полей не несёт префикса длины или разделителя. Rangeproof и scriptPubKey имеют переменную длину; обязательство Педерсена и генератор актива всегда представляют собой 33-байтовые точки. Поэтому дайджест фиксирует только конкатенированные байты, без каких-либо меток, отмечающих, где заканчивается одно поле и начинается следующее. Два разных набора из четырёх полей, которые случайно конкатенируются в одну и ту же последовательность байтов, дают одну и ту же запись, и та проверка, которая пройдёт первой, оставляет вердикт, который заберёт другая. Хешер инициализируется случайной солью, уникальной для каждого узла, но эта соль добавляется в начало обоих потоков одинаково, так что она меняет дайджест, но не различает два входных значения. Дефект был устранён коммитом 94000967 [3].

Анализ атаки

Приведённый ниже анализ основан на транзакциях 271147...187ec5 и f24a4b...0a183f, обе были приняты узлами, работающими на уязвимом коде.

  • Шаг 1: Злоумышленник опубликовал транзакцию, первый выход которой является OP_RETURN, несущим 67 байт данных.

Её scriptPubKey выглядит как 6a 43 — опкод OP_RETURN, за которым следует пуш из 67 байт, — затем два 33-байтовых значения и завершающий 6a. Эти 67 отправленных в стек байт не являются данными, нужными этой транзакции. Это обязательство по значению (value commitment) и генератор актива выхода, который ещё не существовал. Проверка этого выхода сохранила вердикт valid под записью для его собственных четырёх полей.

  • Шаг 2: Затем злоумышленник отправил инфляционную транзакцию. Её выход OP_RETURN имеет scriptPubKey, состоящий из единственного байта 6a, а его обязательство по значению в точности равно 33-байтовому значению, вложенному в пуш предыдущей транзакции. Поле rangeproof было построено из rangeproof, обязательства и генератора актива предыдущей транзакции, за которыми следуют два байта 6a 43.

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

Primer:     P0 │ C0 │ X │ S0,  where S0 = 6a 43 <33-byte C1> <33-byte X> 6a
Inflation:  P1 │ C1 │ X │ S1,  where P1 = P0 ‖ C0 ‖ X ‖ 6a 43  and  S1 = 6a

Both concatenate to:  P0 ‖ C0 ‖ X ‖ 6a 43 ‖ C1 ‖ X ‖ 6a

Кэш вернул более ранний вердикт, а P1 так и не был проверен — это вообще не rangeproof. C1 фиксирует небольшую отрицательную сумму. Другой выход транзакции, обычный выход pay-to-witness-public-key-hash на адрес злоумышленника ex1q7kg...qa2w, нёс крупное положительное обязательство с настоящим rangeproof, и эти два значения компенсировали друг друга, так что транзакция сбалансировалась. В итоге появилось 4000 непотраченных L-BTC, не обеспеченных биткоином.

  • Шаг 3: Злоумышленник осуществил peg-out. Две транзакции сожгли 3,996.01834922 и 2.65138358 L-BTC через обычные выходы peg-out OP_RETURN, всего 3,998.66973280 L-BTC. Функциональные узлы, авторизующие peg-out, проверили их с помощью того же уязвимого кода и высвободили биткоин: 3,995.99999857 BTC и 2.49749857 BTC поступили злоумышленнику в сети Bitcoin, всего 3,998.49749714 BTC.

Сеть приостановила работу и разделилась на две цепи на время урегулирования инцидента [4], а затем возобновила работу с отклонённым недействительным peg-out [2]: обозреватель блоков сегодня показывает подтверждённую первичную транзакцию, но не инфляционную транзакцию, хотя высвобожденный ею биткоин уже покинул кошелёк федерации. На следующий день в 16:09:25 UTC злоумышленник вернул 3,400.00000000 BTC в кошелёк привязки федерации, оставив себе оставшиеся ~598.5 BTC [2], в то время как обе стороны вели переговоры через сообщения, встроенные в транзакции Bitcoin [4].

Заключение

Злоумышленник не взломал никакой криптографии и не скомпрометировал никакой ключ. Дефект заключался в том, как кэш rangeproof идентифицировал то, что уже было проверено. Его ключ конкатенировал четыре поля — два из которых имели переменную длину — в один поток хеширования без каких-либо меток, отмечающих, где заканчивается каждое поле, так что второй набор полей мог заново разбить те же байты и попасть в ту же запись. Сохранённый вердикт valid затем возвращался для доказательства, которое ни один узел никогда не проверял, а как только rangeproof перестаёт ограничивать сумму за собой, конфиденциальный реестр теряет единственное, что удерживало его скрытые значения неотрицательными. Один сконструированный выход превратился в 4000 L-BTC, а двусторонняя привязка превратила их в биткоин в основной цепи.

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


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

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

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

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

Symbiosis

11 сентября 2026 года биткоин-маршрут кросс-чейн моста Symbiosis подвергся эксплойту в его развёртываниях в BNB Smart Chain, Ethereum и Rootstock, что обошлось поставщикам ликвидности и пользователям примерно в 9.97 BTC (~$770K по курсу ~$77K на 11 сентября) [5]. Офчейн-код, определяющий, сколько синтетического биткоина чеканить исходя из депозита в Bitcoin, брал идентичность вносителя из той части транзакции, которую контролирует сам вноситель, что позволило злоумышленнику выдать себя за администратора и опустить минимальную комиссию ниже нуля; затем эта комиссия вычиталась из суммы депозита без проверки знака, так что вычитание фактически становилось прибавлением.

Предыстория

Symbiosis — это протокол кросс-чейн ликвидности, перемещающий стоимость между цепями путём блокировки и чеканки, а не путём передачи самого актива: в цепях со смарт-контрактами токены пользователя блокируются контрактом Portal в исходной цепи, а контракт Synthesis чеканит эквивалентное количество синтетического токена, sToken, в целевой цепи; сжигание sToken высвобождает оригинал [6]. Bitcoin поступает через этот маршрут в виде syBTC — токена с 8 знаками после запятой, соответствующими наименьшей единице самого биткоина, выпускаемого в BNB Smart Chain, Ethereum и Rootstock и объединяемого в пулы с BTCB, cbBTC, WBTC и RBTC [5].

У Bitcoin ничего этого нет: нет смарт-контрактов, а значит, нет и контракта Portal для блокировки депозитов. Вместо этого используется портал — специально выделенный адрес Bitcoin, играющий ту же роль. Депозит — это обычная транзакция Bitcoin, оплачивающая этот адрес, с инструкциями для целевой цепи, прикреплёнными к ней в виде данных. Офчейн-код, принадлежащий мосту, читает эти данные, чтобы узнать, кто делает депозит, сколько и куда должен пойти синтетический токен, и применяет комиссию портала — вычитаемую из внесённой суммы перед фиксацией суммы к чеканке, — минимум которой является параметром, устанавливаемым его администратором.

Ничто на стороне Bitcoin не видно целевой цепи, поэтому Сеть Ретрансляторов (Relayers Network) переносит получившийся запрос через границу. Запрос поступает в BridgeV2, точку входа моста в цепи, в виде закодированного вызова, который перенаправляется в Synthesis. Авторизация основана на MPC-ключе: подписанты протокола владеют долями единого закрытого ключа и совместно формируют одну подпись для запроса. Точка входа для ретранслируемых запросов несёт единственный модификатор и не делает ничего другого перед отправкой вызова:

Этот модификатор хеширует запрос и требует, чтобы сопровождающая подпись была действительна для MPC-адреса:

Контракт устанавливает лишь то, что запрос подписан MPC-ключом. Сумма, которую несёт запрос, вычисляется на стороне Bitcoin.

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

Дефект находится не в контрактах целевой цепи. Он в офчейн-сервисе, который читает депозиты Bitcoin и превращает их в кросс-чейн запросы. Его исходный код публично недоступен, поэтому изложение ниже основано на пост-мортеме команды [5] вместе со сторонним аудиторским отчётом 2024 года, содержащим фрагмент кода, который выглядит связанным с этой проблемой [7].

Два дефекта в пути обработки депозита должны были совпасть, и в пост-мортеме указано, что ни один из них сам по себе не был достаточен.

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

Второй дефект заключается в том, как применяется эта комиссия. В аудите 2024 года была отмечена строка в decodeWrap(), вычисляющая сумму к чеканке путём вычитания комиссии из значения выхода депозита:

Value: types.Satoshi(tx.TxOut[idx].Value) - info.PortalFee,

Вывод аудита заключался в том, что types.Satoshi — это знаковый целочисленный тип, в то время как структура info, несущая PortalFee, является недоверенной и контролируется пользователем, так что результат может быть искусственно сделан отрицательным и, будучи сериализован для целевой цепи как беззнаковое значение, становится достаточно большим, чтобы отчеканить произвольное количество синтетического биткоина. В аудиторском отчёте эта проблема на тот момент была отмечена как исправленная [7]. Пост-мортем 2026 года описывает сбой того же рода: комиссия вычиталась из депозита без проверки знака [5], поэтому комиссия ниже нуля увеличивала депозит, а не уменьшала его. Похоже, что ничто в пути обработки депозита не ограничивает сумму к чеканке реально полученным количеством биткоина.

Анализ атаки

Двенадцать поддельных чеканок прошли в BNB Smart Chain, Ethereum и Rootstock примерно за четыре минуты [5]. Приведённый ниже анализ основан на одной из них — транзакции 0x9a2bc0...21b9b959 в BNB Smart Chain.

  • Шаг 1: Выдав себя за администратора портала, злоумышленник опустил минимальную комиссию, принимаемую порталом, ниже нуля, чтобы депозит, объявляющий отрицательную комиссию, обрабатывался, а не отклонялся [5].

  • Шаг 2: Злоумышленник внёс депозит в 330 сатоши, что отображается как 0x000000000000014a. Запрос, поступивший в BNB Smart Chain, нёс значение 0x400000000000014a — то же самое значение с установленным битом для 2^62, то есть 4,611,686,018,427,388,234 базовых единиц. Разница между двумя значениями в точности равна 2^62, так что комиссия, вычтенная из этого депозита, составила -4,611,686,018,427,387,904 сатоши:

    330 - (-4,611,686,018,427,387,904) = 4,611,686,018,427,388,234

    Запрос был подписан и ретранслирован именно в таком виде.

  • Шаг 3: receiveRequestV2Signed() проверила MPC-подпись запроса и передала его дальше, дойдя до metaMintSyntheticTokenBTC(). Эта функция определила синтетическое представление реального токена для ID исходной цепи, syBTC, и вызвала synthesize() для полной подписанной суммы. Всё это было переведено на адрес злоумышленника 0x025122...5d3Ba2: 46,116,860,184.27388234 syBTC.

  • Шаг 4: Злоумышленник продал синтетический токен в пулы, содержащие его. Единственный своп через пул Uniswap v4 syBTC/WBTC совершил обмен 18,446,744,072,845,450,682 базовых единиц syBTC — примерно вчетверо больше, чем было отчеканено в описанной выше транзакции, — и вывел 4.38897292 WBTC.

Направленная дальше, выручка от этого свопа составила примерно 137 ether.

Команда приостановила биткоин-маршрут, и около 15.2 BTC средств портала были перемещены на резервные адреса в течение нескольких часов [5]. Было предложено вознаграждение в размере 20% от любой возвращённой суммы, действующее до 13 сентября [8]. Другие маршруты протокола не пострадали.

Заключение

Ни один ключ не был украден, и ни один контракт не был обманут для выполнения кода, для которого он не был написан. Подпись, проверенная целевой цепью, была подлинной; то, что она авторизовала, было числом, которое офчейн-код уже некорректно вычислил двумя разными способами: сначала когда он считал идентичность вносителя из поля, контролируемого самим вносителем, позволив злоумышленнику выдать себя за администратора портала и опустить его минимальную комиссию ниже нуля, а затем когда эта комиссия вычиталась из депозита без проверки знака, так что отрицательная комиссия увеличивала депозит вместо того, чтобы его уменьшать.

Идентичность, считанная из недоверенных входных данных, не является идентичностью: привилегированная роль может быть установлена только на основании того, что вноситель не может выбрать самостоятельно, например адреса, который фактически авторизовал потраченный вход, сверенного со списком, который ведёт протокол, — а не поля, которое вноситель волен заполнить произвольно. Значение, которое вычитается, нуждается в ограничениях с обеих сторон: комиссия должна быть обязана лежать в диапазоне от нуля до суммы депозита, а сумма к чеканке никогда не должна иметь возможность превышать фактически полученное исходной цепью. Любое из этих ограничений само по себе остановило бы эту атаку.

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

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

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

Источники

[1] https://x.com/Liquid_BTC/status/2096696272447218108

[2] https://x.com/Liquid_BTC/status/2097404704028545175

[3] https://github.com/ElementsProject/elements/commit/94000967f6dc05b1afd435e79b1bbc597e29f816

[4] https://www.coindesk.com/markets/2026/09/08/white-hat-hackers-return-most-of-usd320m-bitcoin-taken-from-liquid-network

[5] https://x.com/symbiosis_fi/status/2099566361940795831

[6] https://docs.symbiosis.finance/crosschain-liquidity-engine/synthesizing-process

[7] https://github.com/symbiosis-finance/audits/blob/master/Symbiosis%20Relayers%20Network/Symbiosis%20Relayers%20Network%202024%20-%20Decurity.pdf

[8] https://x.com/symbiosis_fi/status/2098442463358718264

О компании BlockSec

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

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

Sign up for the latest updates
Потеряно ~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 — лишь один домен прошёл все. Каких четырёх мер защиты не хватает большинству и почему это критично для пользователя.

Поверхности атаки Web3: обзор тестирования на проникновение

Поверхности атаки Web3: обзор тестирования на проникновение

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

Best Security Auditor for Web3

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

BlockSec Audit