攻擊主要由兩個關鍵步驟組成。第一步是更改守護者(keeper),第二步是提取代幣(執行解鎖功能)。第二步已經得到了充分的分析。對於第一步,Kevin 指出,哈希碰撞是駭客是用來調用 putCurEpochConPubKeyBytes 函數的一種巧妙技巧。然而,攻擊者為何能首先發起一筆有效的交易來進行此調用,目前仍不得而知。
在這篇部落格中,我們使用來自 Ontology 的惡意交易(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c)來闡述整個過程。
總結來說,我們發現:
- Ontology 中繼器(relayer)對於來自 Ontology 鏈的交易缺乏足夠的驗證機制。
- 只要 Poly 鏈上有一個有效的區塊,攻擊者就可以直接調用
EthCrossChainData中的putCurEpochConPubKeyBytes函數,而無需通過 Ethereum 中繼器。 - 正如 Kevin 所指出的哈希碰撞。
免責聲明:本部落格包含我們團隊的分析結果,這些結果基於公開可用的源代碼和鏈上交易。在沒有來自 Poly Network 的進一步資訊前,我們無法驗證我們的結果。
0x.1 交易與合約
攻擊流程
Ontology 交易 -> Ontology 中繼器 -> Poly 鏈 -> Ethereum 中繼器 -> Ethereum
Ethereum
0x838bf9e95cb12dd76a54c9f9d2e3082eaf928270: EthCrossChainManager
0xcf2afe102057ba5c16f899271045a0a37fcb10f2: EthCrossChainData
0x250e76987d838a75310c34bf422ea9f1ac4cc906: LockProxy
Transaction: 0xb1f70464bd95b774c6ce60fc706eb5f9e35cb5f06e6cfe7c17dcda46ffd59581
Ontology
Transaction: 0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c
Poly
Transaction: 0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80
0x2. 攻擊流程
以發生在 Ethereum 上的攻擊為例。 這是一次涉及三條鏈(及其相應中繼器)的「跨鏈攻擊」,即 Ontology 鏈、Poly 鏈和 Ethereum。
整個攻擊流程分為三個步驟:
- 攻擊者首先在 Ontology 鏈上發起了惡意交易(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c);
- 攻擊者隨後修改了存儲在 Ethereum 上
EthCrossChainData合約中的守護者公鑰; - 攻擊者最後精心策劃了一筆惡意交易,以竊取加密資產。
0x2.1 第一步
攻擊者首先從 Ontology 發起了一筆跨鏈交易(0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c),其中包含惡意負載:

您可能注意到該負載包含一個偽造的函數名稱(以 6631 開頭,轉換後為 f1121318093)。這個名稱肯定是精心設計的,因為攻擊者利用函數簽名的哈希碰撞,用它來調用 putCurEpochConPubKeyBytes 函數(請參見 Ethereum 上的 EthCrossChainData 合約)。這裡我們不再詳細說明哈希碰撞的細節,因為相關討論已經非常多。
此後,該交易被 Ontology 鏈中繼器成功接收。請注意,這裡不存在任何嚴格的驗證。因此,它在 Poly 鏈上成為了一筆有效的新交易(0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80)。
這筆新交易隨後被 Ethereum 中繼器檢測到並被拒絕,因為 Ethereum 中繼器驗證了目標合約地址(本例中為 EthCrossChainData),但實際上只允許調用 LockProxy。
因此,處理程序終止。然而,該帶有惡意負載的交易已存儲在 Poly 鏈上,可被利用來發動攻擊。
0x2.2 第二步
攻擊者通過調用 EthCrossChainManager 合約的 verifyHeaderAndExecuteTx 函數,手動向 Ethereum 發送了交易。存儲在 Poly 鏈上的惡意交易數據被用作輸入。作為一筆有效的 Poly 鏈交易,它能夠繞過 verifyHeaderAndExecuteTx 函數中的驗證(包括簽名和默克爾證明)。隨後,EthCrossChainData 合約的 putCurEpochConPubKeyBytes 函數被調用,將原本的四個守護者修改為由攻擊者控制的新守護者(即 0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B)。
0x2.3 第三步
在修改守護者之後,攻擊者可以直接調用 verifyHeaderAndExecuteTx 函數,無需使用 Poly 鏈。最後,調用了 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 鏈的跨鏈交易,以及檢查跨鏈交易狀態的常式(第 71 行)。

在上圖中,Ontology 中繼器調用了 Ontology 鏈公開的 RPC 接口(第 215 行 GetSmartContractEventByBlock)來獲取鏈上記錄的事件。從第 228 行和 232 行可以看出,該常式僅監聽由 CrossChainContractAddress 觸發的 makeFromOntProof 事件。

在上圖中,處理跨鏈交易時有五項檢查。前兩項檢查是對 Ontology 鏈的 RPC 請求(檢查 1 和 4),以及三項檢查參數是否為空(檢查 2、3 和 5)。然而,對於跨鏈交易的語義,即合約和方法名稱是否合理,並沒有任何檢查。最後,它將交易發送到 Poly 鏈(第 183 行)。

Ontology 中繼器使用 RPC 接口(第 164 行 - SendTransaction)構建並發送交易到 Poly 鏈。

函數 ProcessToAliianceCheckAndRetry 只檢查交易是否失敗。如果失敗,它會重新發送交易。
總結來說,ont-relayer 監聽由 Ontology 鏈上 CrossChainContractAddress 觸發的所有 makeFromOntProof 事件。然後該交易將被發送到 Poly 鏈。請注意,來自 Ontology 鏈上任何人的跨鏈交易都會觸發 makeFromOntProof 事件,從而導致交易被發送到 Poly 鏈。
0x3.2 繞過 Ethereum 中繼器
Ethereum Relayer 負責監聽來自 Poly 鏈的交易,然後將交易發送到 Ethereum。

Ethereum 中繼器啟動了一個 Goroutine 來監控 Poly 鏈;

它監控目標為 Ethereum 的跨鏈交易(第 275 - 278 行)。然後檢查目標合約(ToContractAddress)是否為 config.TargetContracts 中配置的合約之一。如果不是,跨鏈交易將不會發送到目標鏈(Ethereum)。
然而,攻擊者可以直接與目標鏈交互並調用 EthCrossChainManager 中的函數。換句話說,Ethereum 中繼器中的檢查是可以被繞過的。只要惡意交易已經被打包在 Poly 鏈上(這是在上一步通過 Ontology 中繼器實現的),攻擊者就可以直接與 EthCrossChainManager 交互。在此過程中,由於 Poly 鏈上存在一筆有效的交易,簽名驗證(ECCUtils.verifySig)和默克爾證明(ECCUtils.merkleProve)都能通過。
通過使用上述兩種方法,攻擊者可以成功調用 Ethereum 上的 ToContractAddress.method。結合哈希碰撞,putCurEpochConPubKeyBytes 函數最終被調用以更改守護者。
貢獻者
Yufeng Hu, Siwei Wu, Lei Wu, Yajin Zhou @ BlockSec
官方 Twitter:https://twitter.com/BlockSecTeam



