攻撃は主に2つのステップで構成されます。最初のステップはキーパーを変更し、2番目のステップはトークンを引き出す(unlock関数を実行する)ことです。2番目のステップは完全に分析されました。最初のステップについては、Kevinが、ハッシュ衝突がハッカーがputCurEpochConPubKeyBytes関数を呼び出すために使用した巧妙なトリックの1つであると指摘しています。しかし、なぜ攻撃者がそもそもこの呼び出しを行うための有効なトランザクションを持っていたのかは不明のままです。
このブログでは、Ontologyからの悪意のあるトランザクション(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c)を使用して、プロセス全体を説明します。
要約すると、以下のことがわかりました。
- Ontologyのリレイヤーには、Ontologyチェーンからのトランザクションに対する十分な検証メカニズムがありません。
- 攻撃者は、Polyチェーン上に有効なブロックがある限り、Ethereumリレイヤーを経由せずに、
EthCrossChainData内のputCurEpochConPubKeyBytes関数を直接呼び出すことができます。 - Kevinが指摘したハッシュ衝突
免責事項: このブログには、公開されているソースコードとオンチェーントランザクションに基づいた、当社のチームによる分析結果が含まれています。Poly Networkからの追加情報なしには、結果を検証することはできません。
0x.1 トランザクションとコントラクト
攻撃フロー
Ontologyトランザクション -> Ontologyリレイヤー -> Polyチェーン -> Ethereumリレイヤー -> Ethereum
Ethereum
0x838bf9e95cb12dd76a54c9f9d2e3082eaf928270: EthCrossChainManager
0xcf2afe102057ba5c16f899271045a0a37fcb10f2: EthCrossChainData
0x250e76987d838a75310c34bf422ea9f1ac4cc906: LockProxy
トランザクション: 0xb1f70464bd95b774c6ce60fc706eb5f9e35cb5f06e6cfe7c17dcda46ffd59581
Ontology
トランザクション: 0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c
Poly
トランザクション: 0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80
0x2. 攻撃フロー
Ethereumで発生した攻撃を例に取ります。 これは3つのチェーン(およびそれに対応するリレイヤー)を伴う「クロスチェーン攻撃」であり、Ontologyチェーン、Polyチェーン、Ethereumです。
攻撃フロー全体は3つのステップで構成されます。
- 攻撃者はまずOntologyチェーンで悪意のあるトランザクション(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c)を開始しました。
- 次に、攻撃者はEthereumの
EthCrossChainDataコントラクトに保存されているキーパーの公開鍵を変更しました。 - 最後に、攻撃者は仮想通貨資産を収集するための悪意のあるトランザクションを作成しました。
0x2.1 最初のステップ
攻撃者はまず、悪意のあるペイロードを含むクロスチェーントランザクション(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c)をOntologyから開始しました。

このペイロードには、細心の注意を払って作成された関数名(「6631」から始まり、変換すると「f1121318093」)が含まれていることに気づくかもしれません。これは、攻撃者が関数シグネチャのハッシュ衝突を悪用して、EthereumのEthCrossChainDataコントラクトのputCurEpochConPubKeyBytes関数を呼び出すために使用するため、非常に巧妙です。ここではハッシュ衝突の詳細については説明しません。よく議論されているためです。
その後、このトランザクションはOntologyチェーンリレイヤーによって正常に受け入れられました。厳密な検証は存在しないことに注意してください。その結果、Polyチェーン上で有効な新しいトランザクション(0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80)になりました。
この新しいトランザクションはEthereumリレイヤーによって認識され、「拒否」されました。なぜなら、Ethereumリレイヤーは宛先コントラクトアドレス(この場合はEthCrossChainData)を検証しましたが、許可されるのはLockProxyのみであったからです。
このようにして、処理は中断されました。しかし、悪意のあるペイロードを持つトランザクションはPolyチェーンに保存されており、攻撃を開始するために悪用される可能性があります。
0x2.2 2番目のステップ
攻撃者は、EthCrossChainManagerコントラクトのverifyHeaderAndExecuteTx関数を呼び出すトランザクションをEthereumに手動で送信しました。Polyチェーンに保存されている悪意のあるトランザクションデータが入力として使用されました。有効なPolyチェーントランザクションとして、verifyHeaderAndExecuteTx関数内の署名とマーケルプルーフを含む検証をバイパスすることができました。その後、EthCrossChainDataコントラクトのputCurEpochConPubKeyBytes関数が呼び出され、元の4人のキーパーが攻撃者が制御する新しいキーパー(0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B)に変更されました。
0x2.3 3番目のステップ
キーパーの変更後、攻撃者はPolyチェーンを使用せずにverifyHeaderAndExecuteTx関数を直接呼び出すことができました。最後に、LockProxyコントラクトのunlock関数が呼び出され、Ethereumから大量のデジタル資産が盗まれました。詳細な分析は、以前のレポートで確認できます。
0x3. リレイヤー
OntologyとEthereumのリレイヤーはどちらもGoで実装されています。しかし、検証が不十分であるため、
- 攻撃者は悪意のあるトランザクションを構築し、それをPolyチェーンにパッキングすることができます。
- 攻撃者はEthereumの
EthCrossChainDataスマートコントラクト内の関数を直接呼び出すことができます。
0x3.1 OntologyリレイヤーはOntologyからのクロスチェーントランザクションを盲目的に信頼する
ont_relayerは、Ontologyチェーンからのクロスチェーントランザクションをリッスンし、それらをPolyチェーンに送信する責任があります。
- SideはOntologyチェーンを指し、AllianceはPolyチェーンを指します。
CrossChainContractAddressはOntologyチェーン上のネイティブスマートコントラクト(番号09)です。

上記の図は、OntologyリレイヤーがOntologyチェーンとの間でクロスチェーントランザクションをリッスンするための2つのルーチンを開始し、クロスチェーントランザクションのステータスをチェックするルーチン(71行目)を示しています。

上記の図では、OntologyリレイヤーはOntologyチェーンからRPCインターフェース(215行目 GetSmartContractEventByBlock)を呼び出して、チェーン上のイベントを取得します。228行目と232行目から、このルーチンはCrossChainContractAddressによってトリガーされたmakeFromOntProofイベントのみをリッスンしていることがわかります。

上記の図では、クロスチェーントランザクションを処理する際に5つのチェックがあります。最初の2つはOntologyチェーンへのRPCリクエスト(チェック1と4)をチェックし、3つはパラメータがnullでないかをチェックします(チェック2、3、5)。しかし、クロスチェーントランザクションのセマンティクス、つまりコントラクトとメソッド名が合理的であるかどうかのチェックは存在しません。最後に、トランザクションはPolyチェーンに送信されます(183行目)。

Ontologyリレイヤーは、RPCインターフェース(164行目 - SendTransaction)を使用して、Polyチェーンへのトランザクションを構築して送信します。

ProcessToAliiance**Check**AndRetry関数は、トランザクションが失敗したかどうかのみをチェックします。失敗した場合、トランザクションは再送信されます。
要約すると、ont-relayerはOntologyチェーンからのすべてのmakeFromOntProofイベントをリッスンします。その後、トランザクションはPolyチェーンに送信されます。Ontologyチェーン上の誰からのクロスチェーントランザクションでもmakeFromOntProofイベントをトリガーし、Polyチェーンに送信される結果になることに注意してください。
0x3.2 Ethereumリレイヤーのバイパス
Ethereum Relayerは、Polyチェーンからのトランザクションをリッスンし、その後トランザクションをEthereumに送信する責任があります。

Ethereumリレイヤーは、Polyチェーンを監視するためのGoroutineを開始します。

これは、宛先がEthereumであるクロスチェーントランザクションを監視します(275〜278行目)。次に、宛先コントラクト(ToContractAddress)がconfig.TargetContractsに設定されているコントラクトのいずれであるかを確認します。そうでない場合、クロスチェーントランザクションは宛先チェーン(Ethereum)に送信されません。
しかし、攻撃者は宛先チェーンと直接対話し、EthCrossChainManager内の関数を呼び出すことができます。言い換えれば、Ethereumリレイヤーでのチェックはバイパスできます。悪意のあるトランザクションがPolyチェーンにパッキングされていれば(前のステップでOntologyリレイヤーを介して達成された)、攻撃者はEthCrossChainManagerと直接対話できます。このプロセス中、Polyチェーン上の有効なトランザクションがあるため、署名検証(ECCUtils.verifySig)とマーケルプルーフ(ECCUtils.merkleProve)はパスします。
これら2つの方法を組み合わせることで、攻撃者はEthereum上でToContractAddress.methodを正常に呼び出すことができます。ハッシュ衝突と組み合わせることで、最終的にputCurEpochConPubKeyBytes関数が呼び出され、キーパーが変更されました。
謝辞
Yufeng Hu, Siwei Wu, Lei Wu, Yajin Zhou @ BlockSec
公式サイト: https://blocksec.com/
公式Twitterアカウント: https://twitter.com/BlockSecTeam



