Атака состоит из двух основных этапов. Первый этап — это смена хранителя (keeper), а второй — вывод токенов (выполнение функции разблокировки). Второй этап был полностью проанализирован. Что касается первого этапа, Kevin отметил, что коллизия хеша — это один из хитроумных приемов, использованных хакером для вызова функции putCurEpochConPubKeyBytes. Однако до сих пор остается неизвестным, как злоумышленник смог изначально получить валидную транзакцию для осуществления этого вызова.
В этом блоге мы используем вредоносную транзакцию из сети Ontology (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c), чтобы проиллюстрировать весь процесс.
Вкратце, мы обнаружили следующее:
- Реле Ontology не имеет достаточных механизмов проверки для транзакций, поступающих из цепочки Ontology.
- Злоумышленник может напрямую вызывать функцию
putCurEpochConPubKeyBytesв контрактеEthCrossChainData, минуя реле Ethereum, при условии, что в цепочке Poly существует валидный блок. - Коллизия хеша, как отметил Кевин.
Отказ от ответственности: Этот блог содержит результаты анализа, проведенного нашей командой, которые основаны на общедоступном исходном коде и транзакциях в блокчейне. Без дополнительной информации от Poly Network мы не можем подтвердить наши результаты.
0x.1 Транзакции и контракты
Поток атаки
Транзакция Ontology -> Реле Ontology -> Цепочка Poly -> Реле Ethereum -> Ethereum
Ethereum
0x838bf9e95cb12dd76a54c9f9d2e3082eaf928270: EthCrossChainManager
0xcf2afe102057ba5c16f899271045a0a37fcb10f2: EthCrossChainData
0x250e76987d838a75310c34bf422ea9f1ac4cc906: LockProxy
Транзакция: 0xb1f70464bd95b774c6ce60fc706eb5f9e35cb5f06e6cfe7c17dcda46ffd59581
Ontology
Транзакция: 0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c
Poly
Транзакция: 0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80
0x2. Поток атаки
Возьмем в качестве примера атаку, произошедшую в сети Ethereum.
Это межсетевая атака (cross-chain attack), затрагивающая три цепочки (и их соответствующие реле): цепочку Ontology, цепочку Poly и Ethereum.
Весь процесс атаки состоит из трех этапов:
- злоумышленник сначала инициировал вредоносную транзакцию (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c) в цепочке Ontology;
- затем злоумышленник модифицировал публичный ключ хранителя, хранящийся в контракте
EthCrossChainDataв сети Ethereum; - в заключение злоумышленник создал вредоносную транзакцию для хищения криптоактивов.
0x2.1 Первый этап
Злоумышленник инициировал кроссчейн-транзакцию (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c) из Ontology, которая содержала вредоносную полезную нагрузку:

Вы можете заметить, что эта полезная нагрузка содержит поддельное имя функции (начинающееся с 6631, что означает f1121318093 после преобразования). Это имя было подобрано весьма тщательно, так как злоумышленник использовал его для вызова функции putCurEpochConPubKeyBytes (см. контракт EthCrossChainData в Ethereum) путем использования коллизии хешей сигнатур функций. Здесь мы не будем вдаваться в детали коллизии хешей, так как эта тема уже широко обсуждалась.
После этого транзакция была успешно принята реле цепочки Ontology. Обратите внимание, что здесь ОТСУТСТВУЕТ какая-либо строгая проверка. В результате она стала валидной новой транзакцией (0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80) в цепочке Poly.
Затем эта новая транзакция была обнаружена и ОТКЛОНЕНА реле Ethereum. Это произошло потому, что реле Ethereum проверило адрес целевого контракта (в данном случае EthCrossChainData), тогда как разрешен был только LockProxy.
Таким образом, процесс был завершен. Однако транзакция с вредоносной полезной нагрузкой была сохранена в цепочке Poly, что и позволило осуществить атаку.
0x2.2 Второй этап
Злоумышленник вручную отправил транзакцию в Ethereum, вызвав функцию verifyHeaderAndExecuteTx в контракте EthCrossChainManager. В качестве входных данных была использована вредоносная транзакция, сохраненная в цепочке Poly. Будучи валидной транзакцией цепочки Poly, она смогла обойти проверку (включая подписи и доказательство Меркла) внутри функции verifyHeaderAndExecuteTx. После этого была вызвана функция putCurEpochConPubKeyBytes контракта EthCrossChainData, которая заменила оригинальных четырех хранителей на нового (т.е. 0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B), подконтрольного злоумышленнику.
0x2.3 Третий этап
После изменения хранителя злоумышленник смог напрямую вызвать функцию verifyHeaderAndExecuteTx, не прибегая к использованию цепочки Poly. Наконец, была вызвана функция unlock контракта LockProxy для кражи огромного количества цифровых активов из сети Ethereum. Подробный анализ можно найти в нашем предыдущем отчете.
0x3. Реле
Оба реле — Ontology и Ethereum — реализованы на Go. Однако им недостает должной проверки, из-за чего:
- Злоумышленник может сформировать вредоносную транзакцию, которая будет упакована в цепочку Poly.
- Злоумышленник может напрямую вызывать функции в смарт-контракте
EthCrossChainDataв сети Ethereum.
0x3.1 Реле Ontology слепо доверяет кроссчейн-транзакциям из Ontology
ont_relayer отвечает за прослушивание кроссчейн-транзакций из цепочки Ontology и их отправку в цепочку Poly.
- Side (Сторона) означает цепочку Ontology; Alliance (Альянс) означает цепочку Poly.
CrossChainContractAddress— это нативный смарт-контракт (номер 09) в цепочке Ontology.

На рисунке выше показано, что реле Ontology запускает две процедуры для прослушивания кроссчейн-транзакций из цепочки Ontology и обратно, а также процедуру для проверки статуса кроссчейн-транзакции (строка 71).

На рисунке выше показано, что реле Ontology вызывает RPC-интерфейс, предоставленный цепочкой Ontology (строка 215, GetSmartContractEventByBlock), для получения событий в цепочке. Начиная со строк 228 и 232 видно, что эта процедура прослушивает только событие makeFromOntProof, вызванное CrossChainContractAddress.

На рисунке выше при обработке кроссчейн-транзакции выполняется пять проверок. Первые две проверяют RPC-запросы (проверки 1 и 4) к цепочке Ontology, а три другие проверяют параметры на предмет того, являются ли они нулевыми (проверки 2, 3 и 5). Однако не существует никакой проверки семантики кроссчейн-транзакции, т.е. являются ли контракт и имя метода разумными. В конце концов, транзакция отправляется в цепочку Poly (строка 183).

Реле Ontology конструирует и отправляет транзакцию в цепочку Poly, используя RPC-интерфейс (строка 164 — SendTransaction).

Функция ProcessToAliianceCheckAndRetry проверяет только то, завершилась ли транзакция неудачей. Если это так, она отправляет транзакцию повторно.
В итоге: ont-relayer прослушивает все события makeFromOntProof, вызванные CrossChainContractAddress из цепочки Ontology. Затем транзакция отправляется в цепочку Poly. Обратите внимание, что кроссчейн-транзакция от любого пользователя в цепочке Ontology запускает событие makeFromOntProof, что приводит к ее отправке в цепочку Poly.
0x3.2 Обход реле Ethereum
Реле Ethereum отвечает за прослушивание транзакций из цепочки Poly и последующую отправку транзакции в Ethereum.

Реле Ethereum запускает Go-рутину для мониторинга цепочки Poly;

Оно отслеживает кроссчейн-транзакции, целью которых является Ethereum (строки 275 - 278). Затем оно проверяет, является ли целевой контракт (ToContractAddress) одним из контрактов, настроенных в config.TargetContracts. Если нет, кроссчейн-транзакция не будет отправлена в целевую цепочку (Ethereum).
Однако злоумышленник может напрямую взаимодействовать с целевой цепочкой и вызывать функцию в EthCrossChainManager. Другими словами, проверку в реле Ethereum можно обойти. До тех пор, пока вредоносная транзакция была упакована в цепочку Poly (что достигается на предыдущем этапе через реле Ontology), злоумышленник может напрямую взаимодействовать с EthCrossChainManager. В этом процессе проверка подписи (ECCUtils.verifySig) и доказательство Меркла (ECCUtils.merkleProve) проходят успешно, так как в цепочке Poly существует валидная транзакция.
Используя два вышеуказанных метода, злоумышленник может успешно вызвать метод ToContractAddress.method в сети Ethereum. В сочетании с коллизией хешей это в конечном итоге приводит к вызову функции putCurEpochConPubKeyBytes для смены хранителя.
Авторы
Юфэн Ху (Yufeng Hu), Сивэй У (Siwei Wu), Лэй У (Lei Wu), Яцзинь Чжоу (Yajin Zhou) @ BlockSec
Официальный сайт: https://blocksec.com/
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



