Wintermute 於 Layer 2 遭攻擊損失 20M $OP

JKOBlockchain
JKOBlockchain
Published in
6 min readAug 2, 2022

今天要分享的是前陣子兩千萬枚 $OP 代幣被攻擊者盜取的事件。這個事件源自於 Wintermute 造市商提供錯誤的地址給 Optimism,導致代幣轉入沒有人擁有的地址,後來卻被攻擊者搶先擁有這個地址。這篇內容我們將以這個事件為背景,介紹 create 和 create2 的概念。

圖片來源:Blockworks

事件

起初,Optimism 基金會聘請 Wintermute 為其在中心化交易所上市的 OP 代幣提供流動性,協議的一部分是 Wintermute 獲得兩千萬枚 OP 代幣作為貸款(Wintermute 也提供 $50M USDC 作為抵押品)。這筆貸款應該是要轉入 Wintermute 在 Optimism 鏈上的地址,但他們卻提供已經部署在以太坊上許久的多簽(multi-sig)Gnosis 金庫地址: 0x4f3a120E72C76c22ae802D129F599BFDbc31cb81。當 Optimism 團隊分別轉移 1 OP 和 1M OP 作為測試時,Wintermute 卻沒有確認真的收到那些代幣就和 Optimism 團隊確認了,所以剩下的 19M 代幣就又在 5/27 轉入了這個錢包地址。

Optimism 團隊先轉了 1 OP 和 1M OP 作為測試,最後才轉剩下的 19M 代幣。資料來源:Optimistic Explorer

Wintermute 提供的地址和普通的錢包地址(EOA, externally owned account)不同,他是一個合約地址,因此擁有在以太坊上這個合約的所有權不代表擁有其他 EVM-compatible 鏈上相同地址的所有權。而這個地址當時在 Optimism 鏈上還沒有所有人。5/30 Wintermute 發現了這個錯誤,並通知了 Gnosis 金庫和 Optimism。經過諮詢後他們宣稱只有他們自己能夠復原那些資金,並計劃在 6/7 將資金取回。

Wintermute 的 Gnosis 金庫地址是 2020 年 由 ProxyFactory 合約(0x76E2)的 createProxy 這個 function 創造的。這個 ProxyFactory 合約在部署時沒有指定的 chainId,因此這個 ProxyFactory 合約在每一條鏈上的合約地址都一樣。此外創建 proxy 合約時,創建出的 proxy 合約其地址只受 sender, nonce 這兩個變數影響,所以在不同的鏈上只要用一樣的 sender 和 nonce 就能得到相同地址的合約。

創建 Gnosis 金庫合約的 Factory 合約 function。資料來源:Etherscan

攻擊者(0x8BcF)在 Optimism 鏈上也創立一個合約(0xE714)去呼叫 Optimism 鏈上的 ProxyFactory(0x76E2)的 createProxy 創造地址直到找到 0x4f3a 的那個地址。下圖可以看到攻擊者在一筆交易一次創建 162 個地址,不斷的重複這樣的交易直到找到符合的地址,最後在這筆交易中創建了與 Wintermute 在以太坊上一模一樣的地址(0x4f3a)。

攻擊者一次創建 162 個地址直到找到與 Wintermute 一模一樣的地址(0x4f3a)。資料來源:Optimistic Explorer

攻擊者將 1M OP 代幣轉入自己的地址,賣掉後獲得大約 720 ETH。幾天後又將 1M 代幣轉入 Vitalik 的錢包地址(0x8da6)。最後將 17M 代幣以一次 1M 的方式歸還到 Wintermute 指定的地址(0x2501),剩餘的 1M Optimism 團隊也同意將總共 2M 的 OP 代幣留給攻擊者作為賞金。

攻擊後先將 1M 代幣轉回自己的地址,4 天後將 1M 代幣轉給 Vitalik。資料來源:Optimistic Explorer

技術點 create/create2

這邊可以介紹兩個以太坊在創建合約時可以用到的 opcode — create 和 create2。

  • create: new_address = hash(sender, nonce)
  • create2: new_address = hash(0xFF, sender, salt, bytecode)

create2 可以說是 create 的升級版,在 EIP-1014 時被提出。create 的缺點是下一個被創建的合約地址是可以被預測的,因為 nonce 會照順序增加。而 create2 則是使部署的地址獨立於未來事件,可以在預先計算出的地址上部署合約。create2 確保如果 sender 用這個 opcode 部署 bytecode 和提供的 salt,它將存儲在 new_address。

上述事件的 ProxyFactory 用的就是 create 而不是 create2,導致攻擊者只要用相同的地址(0x76E2)作為 input 去反覆創建地址就能找到與當初再以太坊上創建給 Wintermute 一樣的合約地址(0x4f3a)。如果這個 ProxyFactory 用的是 create2 的話則需要被部署的合約 bytecode,而因為被部署的是多簽金庫合約,合約內容會有這些共同擁有者(進行多簽的地址們)的地址,因此攻擊者產出的 bytecode 自然會因為與原先的不同,也就無法用 createProxy 去產出相同的地址。

以上的介紹希望有幫助大家了解這個 OP 代幣損失的事件,以及 create 和 create2 這兩個 opcode 的不同。喜歡我們的內容可以幫我們「拍手」,並持續關注我們!

--

--