Введение
Эксперт в области информационной безопасности Гехард Вагнер получил рекордное вознаграждение в размере 2000000$ от команды блокчейн проекта Polygon. Найденная исследователем уязвимость угрожала потерей 850000000$. Вознаграждение стало рекордным в истории DeFi. Гехард Вагнер обратил внимание на баунти-программу, которую Polygon запустил сентябре. Он отметил, что Polygon использует для защиты транзакций между своими сетями и Ethereum систему защиты Plasma, которую, по его мнению, сложно надежно реализовать. Вагнер подробно рассказал о том, как обнаружил уязвимость в «мосте» Plasma Bridge. С помощью ошибки в коде злоумышленник мог бы вывести сумму, в 223 раза превышающую первоначальную стоимость токенов. Внесение каждых $200 тыс. могло бы принести потенциальному хакеру $44,6 млн. В случае эксплуатации уязвимости потери протокола могли составить $850 млн. Вагнер предположил, что проблема возникла «из-за использования стороннего кода без его полного понимания».
Вагнер отметил, что ранее уже работал над системами защиты от мошенничества, в частности над «Плазмой» и знал основные сложности, с которыми сталкиваются разработчики. Поэтому сразу начал проверять опубликованные контракты, чтобы найти тот, который блокирует средства на L1, когда пользователи переводят средства в сеть Polygon и из нее. Он быстро нашел нужный контракт Deposit Manager Proxy, и на момент написания он содержал токены стоимостью около миллиарда долларов США.
Далее разберем найденную уязвимость.
Что такое Polygon и Plasma
Прежде чем анализировать ошибку, важно понять, как работает Plasma и Polygon, по крайней мере, на высоком уровне.
Сначала немного терминологии, кто знаком может пропустить:
Дерево Меркла - полное двоичное дерево, в листовые вершины которого помещены хеши от блоков данных, а внутренние вершины содержат хеши от сложения значений в дочерних вершинах. Корневой узел дерева содержит хеш от всего набора данных, то есть хеш-дерево является однонаправленной хеш-функцией.
Решения второго уровня/слоя (L2-решения) — это проекты, приложения и технологии инфраструктурного программного обеспечения, развернутые поверх базовых блокчейнов.
Сайдчейны — технология, позволяющие токенам и другим цифровым активам одного блокчейна безопасным образом использоваться в другом блокчейне и затем (в случае необходимости) быть возвращенными в оригинальный блокчейн. Изначально концепция сайдчейнов (side chain) была описана в 2014 году в «белой бумаге» (white paper), который написали разработчики компании Blockstream. Сайдчейн (side chain) представляет собой отдельный блокчейн с двусторонней привязкой к родительскому блокчейну. Это обеспечивает взаимозаменяемость активов. Родительский блокчейн обычно называется «основной (главной) цепью» (master chain), дополнительные цепи — сайдчейнами (side-chain). Пользователь родительского блокчейна должен сначала отправить монеты на выходящий адрес, где они «запираются» участниками так называемой «федерации», что призвано исключить возможность их траты в другом месте. По завершении транзакции ее участники получают подтверждение, однако для дополнительной безопасности это происходит после некоторого периода ожидания. После этого эквивалентное количество монет переводится в сайдчейн (side chain), и у пользователя появляется возможность их потратить. При отправке монет из сайдчейна (side chain) в основной блокчейн происходит обратный процесс.
Fraud proof - модель безопасности для решений второго уровня, в которых для повышения скорости из транзакций формируются пакеты и отправляются в Ethereum за одну транзакцию. Они считаются валидными, но могут быть оспорены по определенным правилам. Этот метод увеличивает количество возможных транзакций при сохранении достаточного уровня безопасности.
Plasma — решение второго уровня для масштабирования сети Ethereum, изначально предложенное Джозефом Пуном и Виталиком Бутериным. Технология предусматривает использование смарт-контрактов и деревьев Меркла для создания неограниченного числа дочерних цепей — копий родительской сети Ethereum. Они разгружают основной блокчейн, открывая возможность осуществления быстрых и недорогих транзакций. По принципу работы Plasma похожа на Lightning Network: набор умных контрактов, позволяющий множеству сайдчейнов фиксировать свое состояние в сжатом виде в корневом блокчейне. Plasma применяет экономические стимулы, включая наказание отвергнутого сетью создателя блока для предотвращения мошенничества. В июне 2020 года работающая над масштабированием Ethereum компания OMG Network запустила бета-тестирование OMG Network V1, базирующейся на спецификациях последней версии Plasma — More Viable Plasma (MoreVP). MoreVP масштабирует Ethereum, группируя транзакции и отправляя их через набор смарт-контрактов. Сгруппированные данные проходят верификацию и валидацию в децентрализованной сети хранителей. Группирование позволяет увеличить пропускную способность сети до тысяч транзакций в секунду и значительно сократить их стоимость. Это отдельный блокчейн, который привязан к основной цепочке Ethereum и использует fraud proofs (Optimistic rollups) для разрешения споров.
Matic Network (теперь Polygon) — решение второго уровня с поддержкой фреймворка Plasma и децентрализованной сети PoS-валидаторов. Проект использует сайдчейны (side chain) для офчейн-вычислений. В начале 2021 года состоялся ребрендинг проекта. Сменилось название на Polygon, изменилась стратегия в сторону создания мультичейн-системы, похожей на Polkadot. Команда проекта работает над созданием решений второго уровня на базе Ethereum. Polygon - это протокол и платформа для создания и подключения блокчейн-сетей, совместимых с Ethereum. Платформа предлагает «надежный двусторонний канал транзакций» между Polygon и Ethereum. Этот «блокчейн-мост» использует сеть под названием Plasma для аутентификации и обработки вывода средств. Именно в контракте на Plasma, доверенном лице управляющего депозитами, был обнаружен недостаток.
Архитектура Polygon Network
В архитектуре протокола содержатся 3 абстрактных слоя:
-
Polygon Ethereum смарт-контракты - набор смарт-контрактов на Ethereum, которые обрабатывают:
Стейкинг (Staking) для поддержания Proof-of-Stake;
Управление делегированием, включая общие ресурсы валидатора;
Plasma контракты для MoreVP, включающие checkpoints/snapshots для сайдчейна (side chain).
Heimdall (Proof of Stake layer) – PoS валидатор, который работает на основе Ethereum-контрактов для реализации PoS механизма в Polygon. Он отвечает за проверку блоков, продюсер (block producer).
Bor (Block producer layer) – ответственный за объединение транзакций в блоки. В настоящее время это базовая реализация Geth с некоторыми изменениями, внесенными в алгоритм консенсуса.
На приведенной ниже диаграмме показан поток пользовательских средств через Polygon network (source):
Пользователь вносит средства в контракт моста в L1 (основной сети Ethereum);
После подтверждения транзакции депозита в сети Ethereum, токены доступны в сети Plasma, чтобы пользователи могли их передавать;
Когда пользователь решает вывести средства обратно на L1, токены необходимо сжечь в Plasma. Нужно дождаться контрольной точки. Затем контрольная точка отправляется в мастер-чейн (master chain);
Когда контрольная точка пройдена, выпускаются Exit NFT (ERC721);
Далее необходимо подождать 7 дней;
После 7-дневного периода проверки средства могут быть выведены обратно пользователю на L1.
Такой механизм типичен для fraud proof систем, поскольку они предполагают, что определенные действия являются действительными, и отменяют их только в том случае, если другой пользователь может доказать, что они были недействительными.
Разбор уязвимости
Логика вывода средств обратно в блокчейн Ethereum реализована, в частности, в контракте ERC20PredicateBurnOnly. Выход можно запустить, вызвав функцию startExitWithBurntTokens из данного контракта. В контракте WithdrawManager, также отвечающего за вывод средств, в функции verifyInclusion в строке 115 происходит проверка, включена ли квитанция в дерево. Уязвимость в том, как Polygon WithdrawManager проверяет включение и уникальность в предыдущих блоках.
Одним из параметров, который содержит доказательство выхода, является branchMask. branchMask должна быть уникальной, так как она используется для генерации идентификатора выхода (Exit ID). Важное свойство - одна транзакция есть один идентификатор выхода, но это свойство может быть нарушено. Если проверки пройдены, то идентификатор выхода (Exit ID) создается на основе метки времени, номера блока контрольной точки и branchMask, см. строку 158.
Идентификатор выхода возвращается и сохраняется в приоритетной очереди, которая упорядочивает все выходы в зависимости от их возраста. Когда выход находится в очереди приоритетов не менее 7 дней с момента транзакции, на которую он ссылается, он может быть обработан, и средства возвращаются пользователю в L1.
Идентификатор выхода частично состоит из branch mask, которая поступает непосредственно из пользовательского ввода, что является слабым местом. Если бы было возможно создать альтернативную branch mask, которая каким-то образом способна создать более одного идентификатора выхода, относящегося к одной и той же транзакции. Более пристальный взгляд на функцию в библиотеке MerklePatricaProof показывает, что что-то происходит с путем до того, как будет пройден цикл из строки 40. В строке 35 branch mask передается в функцию _getNibbleArray.
Проверка функции _getNibbleArray показывает, что branch mask (аргумент функции encodedpath) закодирована (Hex Prefix encoded).
Функция _getNibbleArray проверяет с какого значения начинается переданный набор. Если первая часть байта (цифра) 1 или 3, то учитывается вторая часть первого байта и декодируются все оставшиеся значения, иначе первый байт игнорируется. Давайте рассмотрим на примере и предположим, что branch mask равна 0x00819c. Первый байт отбрасывается, так как он – 0, и его первая часть не равна 1 или 3, а остальные фрагменты расширяются до 0x0801090c.
Также в функции verifyInclusion преобразуется branchMask в uint256.
Так как getNibbleArray отбрасывает часть информации, то получаем, что одному значению декодирования getNibbleArray соответствуют несколько uint256 значений. В общей сложности можно создать 14x16 = 224 различных кодировок для одного и того же пути. Злоумышленник может использовать эту проблему для создания альтернативных выходов для одной и той же транзакции и выполнения двойных трат в сети Polygon.
Влияние
Для успешной атаки существуют требования к капиталу, но они минимальны по сравнению с потенциальным вознаграждением злоумышленника. Давайте рассмотрим пример и поймем, сколько мог бы получить злоумышленник по сравнению со средствами, необходимыми для атаки.
Атакующий:
депонирует токены на сумму 200 000 долларов США в контракт DepositManager;
запускает процесс вывода выхода (withdrawal);
ожидает семидневный период проверки;
запускает вывод, переиспользуя предыдущие данные с модифицированным параметром branch mask.
С помощью описанной выше техники генерируются 223 альтернативных выходных полезных нагрузки, и для каждой из них инициируются выходы. Все выходы получают уникальный идентификатор и добавляются в очередь. После того, как все выходы были запущены и обработаны, злоумышленник получает сумму, в 223 раза превышающую сумму первоначального депозита или токенов на сумму 44,6 миллиона долларов.
Исправление
Уязвимость была устранена путем отклонения любой кодировки, которая не начинается с 0x00. Это не очень элегантно, но исправляет ошибку с двойными расходами, жестко кодируя метасимвол кодировки.
https://github.com/maticnetwork/contracts/commit/283b8d2c1a9ff3dc88538820ffc4ea6a2459c040
Комментарии (5)
ifap
12.11.2021 16:27+1Интересно, награду выплатили реальными деньгами или
деревянными членамитеми же фантиками?langoner
12.11.2021 16:54+1Вот, что написано в правилах их программы https://immunefi.com/bounty/polygon/
Payouts are handled by the Polygon team directly and are denominated in USD. However, payouts are done in ETH, MATIC, or a stablecoin, at the discretion of the Polygon team.
1tsov
В вашей компании есть подобная программы вознаграждения?
langoner
Пока нет, но все возможно!
Вообще, данный случай конечно уникальный, столь внушительные суммы можно увидеть только в области криптовалют.