2021 年 08 月 10 日,據慢霧區消息,跨鏈互操作協議 Poly Network 遭受黑客攻擊,慢霧安全團隊第一時間介入分析,并將分析結果分享如下。
攻擊背景
Poly Network 是由 Neo、Ontology、Switcheo 基金會共同作為創始成員,分布科技作為技術提供方共同發起的跨鏈組織,
如下圖,通過官方的介紹我們可以清楚的看出 Poly Network 的架構設計:用戶可以在源鏈上發起跨鏈交易,交易確認后由源鏈 Relayer 將區塊頭資訊同步至 Poly Chain,之后由 Poly Chain 將區塊頭資訊同步至目標鏈 Relayer,目標鏈 Relayer 將驗證資訊轉至目標鏈上,隨后在目標鏈進行區塊頭驗證,并執行用戶預期的交易。
以下是本次攻擊涉及的具體地址:
攻擊核心
1、源鏈未對發起的跨鏈操作的數據進行檢查。
2、目標鏈未對解析出的目標調用合約以及調用參數進行檢查,
3、EthCrossChainData 合約的 owner 為 EthCrossChainManager。
4、 bytes4(keccak256(abi.encodePacked(_method, “(bytes,bytes,uint64)”))) 可以被 hash 碰撞,
攻擊細節
Poly Network 會在各個鏈上部署智能合約以便進行跨鏈互操作(分析將以在以太坊部署的智能合約為例),其中 EthCrossChainManager 合約用于驗證 Poly Chain 同步來的區塊頭以確認跨鏈資訊的真實,EthCrossChainData 合約用于存儲跨鏈數據,中繼鏈驗證人 (即 Keeper) 的公鑰也存儲在這個合約中。LockProxy 則用于資產管理,
本次攻擊中,攻擊者分兩步來完成這次攻擊,我們接下來進行詳細分析:
首先攻擊者通過在其他鏈調用 crossChain 函數構造數據發起跨鏈交易。
我們切入此函數進行分析 :
EthCrossChainManager.crossChain
(https://github.com/polynetwork/eth-contracts/blob/master/contracts/core/crosschainmanager/logic/EthCrossChainManager.sol#L91)
從上圖我們可以清晰的看出,此函數只是用于幫助用戶構造 makeTxParam 并存儲了構造后的哈希以便后續驗證,其并未對用戶傳入的跨鏈操作參數進行任何限制,因此攻擊者完全可以通過構造任意想構造的數據而讓 Relayer 毫無防備的將其同步至 Poly Chain,通過 Poly Chain 將其同步至以太坊 Relayer,
隨后在以太坊上的 Relayer 通過調用 EthCrossChainManager 合約中
的 verifyHeaderAndExecuteTx 函數提交區塊頭資訊來驗證這筆跨鏈資訊的真實性,
我們切入此函數進行分析:
EthCrossChainManager.verifyHeaderAndExecuteTx
(https://github.com/polynetwork/eth-contracts/blob/master/contracts/core/crosschainmanager/logic/EthCrossChainManager.sol#L127)
通過上圖代碼我們可以看出其先對區塊頭進行反序列化,以解出所需要驗證的具體資訊。隨后調用 getCurEpochConPubKeyBytes 函數從 EthCrossChainData 合約中獲取 Keeper 公鑰,并通過 deserializeKeepers 函數得到 Keeper 地址,
接下來將通過 ECCUtils.verifySig 驗證簽名是否為 Keeper,從以下代碼中我們可以發現 verifySig 函數中會切出簽名者的 v r s,并通過 ecrecover 接口獲取簽名者地址,然后調用 containMAddresses 函數循環比較簽名者是否為 Keeper,只要 Keeper 簽名數量符合要求即可通過檢查,數量要求即為 EthCrossChainManager 合約傳入的 n – ( n – 1) / 3)。
簽名驗證后會通過 ECCUtils.merkleProve 進行默克爾根驗證,只要是正常跨鏈操作即可通過此項檢查,隨后會對交易是否重復發送進行檢查并存儲已驗證后的數據。這里只需保證不重復提交即可,
最后,也是最關鍵的一步,其將通過內部調用_executeCrossChainTx 函數執行構造的數據,_
_
從上圖我們可以看出_executeCrossChainTx 函數未對傳入的_toContract、_method 等參數進行檢查就直接以_toContract.call 的方式執行交易。
其中通過鏈上數據我們可以看出 EthCrossChainData 合約的 owner 即為 EthCrossChainManager 合約,而先前我們知道中繼鏈驗證人 (即 Keeper) 的公鑰存在 EthCrossChainData 合約中,且此合約存在 putCurEpochConPubKeyBytes 函數可以直接修改 Keeper 公鑰。
經過以上分析,結果已經很明確了,攻擊者只需在其他鏈通過 crossChain 正常發起跨鏈操作的交易,此交易目的是為了調用 EthCrossChainData 合約的 putCurEpochConPubKeyBytes 函數以修改 Keeper 角色。隨后通過正常的跨鏈流程,Keeper 會解析用戶請求的目標合約以及調用參數,構造出一個新的交易提交到以太坊上,這本質上也只是一筆正常的跨鏈操作,因此可以直接通過 Keeper 檢查與默克爾根檢查,最后成功執行修改 Keeper 的操作,
但我們注意到 putCurEpochStartHeight 函數定義為
function putCurEpochConPubKeyBytes(bytes calldata curEpochPkBytes) external returns (bool);
而_executeCrossChainTx 函數執行的定義為
abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, “(bytes,bytes,uint64)”)))
我們可以知道這兩個函數的函數簽名在正常情況下傳入的_method 為 putCurEpochStartHeight 肯定是完全不同的,因此通過_toContract.call 理論上是無法調用到 putCurEpochStartHeight 函數的,但_method 是攻擊者可以控制的,其完全可以通過枚舉各個字符組合以獲得與調用 putCurEpochConPubKeyBytes 函數相同的函數簽名,這要求其只需枚舉前 4 個字節符合即可。我們也可以自己嘗試枚舉驗證,如下所示:
可以看出前四個字節與 putCurEpochConPubKeyBytes 函數是一致的
至此我們就已還原出攻擊者的攻擊細節,
通過解析鏈上數據,我們可以發現攻擊者將 Keeper 替換為了
0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B,
最后攻擊者只需使用替換后的 Keeper 地址進行簽名即可通過所有檢查執行調用 LockProxy 合約將其管理的資產轉出,
攻擊流程
1、攻擊者在源鏈精心構造一筆修改目標鏈 Keeper 的操作,
2、利用官方 Relayer 正常在目標鏈提交數據并執行替換 Keeper 操作,
3、攻擊者通過替換后的 Keeper 地址對其轉出資產的操作進行簽名提交至 EthCrossChainManager 進行驗證。
4、驗證 Keeper 為攻擊者已替換完的地址通過檢查,執行將資產轉移至攻擊者指定地址,
5、獲利走人,
MistTrack 分析過程
慢霧 AML 團隊分析統計,本次攻擊損失共計超 6.1 億美元!
具體如下:
資金流向分析
慢霧 AML 旗下 MistTrack 反洗錢追蹤系統分析發現,攻擊者初始的資金來源是門羅幣 (XMR),
然后在交易所里換成了 BNB/ETH/MATIC 等幣種并分別提幣到 3 個地址,不久后在 3 條鏈上發動攻擊,
事件梳理
資金情況 (截止到臺北時間 08 月 11 日 13:00)
BSC 上:
黑客地址 1,黑客將近 1.2 億美元(包括約 3210 萬枚 BUSD 和約 8760 萬枚 USDC)的流動性添加到 Curve 分叉項目 Ellipsis Finance 中,目前仍在做市無異動。
Polygon 上:
資金無異動。
Ethereum 上:
1)黑客地址 3,只有一筆轉出 13.37 ETH 到地址
0xf8b5c45c6388c9ee12546061786026aaeaa4b682 的交易;
2)黑客在 Curve 上添加了超 9706 萬美元(包括 67 萬枚 DAI 和 9638 萬枚 USDC)的流動性。后又撤銷流動性將 9638 萬枚 USDC 和 67 萬枚 DAI 換成 9694 萬枚 DAI,這筆資金仍停留在地址 3。目前,3343 萬枚 USDT 已被 Tether 凍結。
疑難問答
注:eccm 為 EthCrossChainManager 合約的簡稱,eccd 為 EthCrossChainData 合約的簡稱。
問:為什么 keeper 能更換成功,合約代碼沒有進行鑒權嗎?
答:eccd 合約有進行鑒權,僅允許 owner 調用 putCurEpochConPubKeyBytes 更改 keeper,因為 eccd 合約的 owner 是 eccm,所以通過 eccm 可以更改 keeper 的值。
問:為什么能簽名一筆更換 keeper 的交易?
答:因為跨鏈要執行的數據沒有判斷好 toContract,所以可能原先的 keeper 以為是一筆正常的跨鏈交易就簽名了 , 但是他是一筆更換 keeper 的交易,
問:為什么能繞過代碼 bytes4(keccak256(abi.encodePacked(_method, “(bytes,bytes,uint64)”))) 的這個限制,然后執行 putCurEpochConPubKeyBytes(bytes) 函數?
答:函數簽名用的是 keccak-256 進行哈希,然后取前面的 4bytes,這種情況下是較容易被 hash 碰撞的,
問:黑客更換 keeper 的交易如何被舊的 keepers 簽名?
答:keepers 是一個鏈中繼器 (Replayer),會對所有正常用戶的跨鏈請求進行簽名,當用戶在 BSC 上發起跨鏈交易時,keepers 會解析用戶請求的目標合約以及調用參數,構造出一個新的交易提交到以太坊上,并在以太坊上用 eccm 合約調用用戶交易里包含的目標合約,黑客替換 keeper 的交易本質上也是一筆正常的跨鏈交易,只不過調用的目標合約是 eccd 合約,調用的參數是更換 keeper,所以能被正常簽名,
總結
本次攻擊主要在于 EthCrossChainData 合約的 keeper 可由 EthCrossChainManager 合約進行修改,而 EthCrossChainManager 合約的 verifyHeaderAndExecuteTx 函數又可以通過_executeCrossChainTx 函數執行用戶傳入的數據,因此攻擊者通過此函數傳入精心構造的數據修改了 EthCrossChainData 合約的 keeper 為攻擊者指定的地址,并非網傳的是由于 keeper 私鑰泄漏導致這一事件的發生。
慢霧 AML 旗下 MistTrack 反洗錢追蹤系統將持續監控被盜資金的轉移,拉黑攻擊者控制的所有錢包地址,提醒交易所、錢包注意加強地址監控,避免相關惡意資金流入平臺。此外, 特別感謝虎符 Hoo、Poly Network、火幣 Zlabs、鏈聞、WePiggy、TokenPocket 錢包、Bibox、歐科云鏈等團隊及許多個人伙伴在合規的前提下及時與慢霧安全團隊同步相關攻擊者資訊,為追蹤攻擊者爭取了寶貴的時間。
目前,在多方努力下,黑客開始陸續歸還資金。