相關報導:PeckShield:去中心化借貸項目Qubit遭黑客攻擊,損失約8000萬美元
作者:yudan(蛋蛋的區塊鏈筆記)
來源:藏在EOA 地址裡的魔法— Qubit Finance 被黑分析
前言
2022 年1 月28 日,一大早醒來就看見ps 那邊預警了Qubit Finance 被黑了。有點慘,這是印像中pancake bunny 項目不知道第幾次被黑了(這裡默哀。。)。然後順著Qubit Finance 官方的推特,不難找到這次的攻擊者地址為
https://bscscan.com/address/0xd01ae1a708614948b2b5e0b7ab5be6afa01325c7
既然知道了地址,那麼老樣子,話不多說,直接開始分析吧:D
攻擊細節分析
由於通過Qubit Finance 我已經拿到了攻擊者的具體地址,所以我就直接對BSC 上的攻擊者地址進行查詢,看看是做了什麼操作。
通過追查攻擊者在BSC 鏈上的操作,發現攻擊者根本沒有什麼準備資金啊,部署攻擊合約之類的操作,直接上來就是borrow, 這種操作很陌生,只有兩種可能,要不就是這個borrow有問題,直接就是通過borrow就借空所有資產,還有一種可能就是,這裡不是第一案發現場。為了驗證這種想法,就需要先看看對應的borrow函數是什麼鬼。
簡單一看這個borrow函數,明顯是屬於Compound的架構,是有抵押品才能進行對應的抵押的,同時#238的borrowAllowed函數我也檢查過確實是有正確實現對代幣價值的檢查的。那就說明第一種假設不成立,也就是說,這裡確實不是第一案發現場。那麼如果借貸的邏輯是正確的,那麼攻擊者理論上來說,會收到由於第一案發現場弄過來的錢來進行借貸。那麼攻擊者的錢又是怎麼來的呢?帶著這個疑問,不妨看下攻擊者地址的代幣轉移情況。
通過追查攻擊者的代幣轉移情況,發現攻擊者在對Qubit Finance 進行借貸之前,就已經在其他地方神秘的收到了好幾筆大額的qXETH代幣,那麼這也驗證了我們的想法,說明借貸操作已經是攻擊後行為了,並不是第一案發現場,為了弄明白這些神秘的資金是怎麼來的,我們需要選取其中的一筆交易進行分析(https://bscscan.com/tx/0x8c5877d1b618f29f6a3622cb610ace08ca96e04d8218f587072a3f91e8545bdc)
通過分析這筆交易,發現這筆交易其實是調用了Qubit Finance的Qbridge合約的voteProposal函數。
但是問題是這個voteProposal其實是只有合約指定的relayer才能進行調用的,難道是Relayer的私鑰洩漏了嗎?正常來說如果不了解Qubit Bridge的架構的話,得出這個結論是顯而易見的。
但是似乎事實並不是這麼簡單。有一種神秘的感覺告訴我事情並不是這樣的。正常來說,對於這種relayer架構的跨鏈,如果是通過relayer進行的操作的話,那麼一定會有一步在其他鏈進行的跨鏈操作,聲明了一個event,然後才有relayer同步到這個event然後開始對應代幣的跨鏈,就像anySwap一樣,那麼基於這種假設,同時攻擊者跨鏈的又是ETH, 那麼攻擊者是大概率在ETH鏈上進行了一次跨鏈操作的。為了驗證這個想法,我去查了一下ETH鏈上的攻擊者的行為,果不其然。 。 。
可以看到攻擊者確實進行了很多筆跨鏈操作,調用了QBridge在以太坊上的合約進行代幣的跨鏈,看來這裡就是第一案發現場了,選取其中的一筆交易進行分析,發現更加異常的地方。
理論上攻擊者應該跨鏈ETH到BSC鏈上,但是這筆交易裡既沒有ETH的轉賬,也沒有WETH的轉移,是怎麼回事呢?這需要我們追踪對應合約的deposit函數來進行分析
通過查看這個代碼,我們不難發現,如果要跨鏈接ETH,根據代碼的函數命名來看,應該是要調用depositETH函數的,但是攻擊者卻調用了deposit函數來進行ETH的跨鏈?為什麼可以這樣?回顧上文說的架構,我們知道,Relayer架構是依賴event消息進行進行跨鏈的,而這depositETH和deposit這兩個函數,是聲明同一個event的,那麼就是說,如果有機會能讓deposit函數聲明的event的參數就是ETH代幣跨鏈的參數的話,depositETH和deposit這兩個函數實現的效果其實是一樣的,那麼問題到這裡就簡化了,由於這兩個函數的傳參都是一樣的,只要按調用depositETH的參數來調用deposit不就好啦?
思路是對的,但是這裡還有一個問題,別忽略了#208 行的handler檢查,這個檢查是deposit函數和depositETH函數都有的,按上面的這個思路,能通過檢查嗎?為了驗證這個想法,我們要去看對應handler合約的的代碼
通過分析handler合約的代碼,發現handler同樣存在deposit函數和depositETH函數,同時,deposit函數是在#128行有白名單檢查的,配合圖中標註的#135 行的safeTransferFrom調用也就是說,攻擊者理論上是要轉移代幣的,而攻擊者的的攻擊交易中,沒有出現代幣的轉移,理論上這裡應該要報錯才對?為什麼成功了呢?回看代碼,tokenAddress的獲取是通過resourceIDToTokenContractAddress進行獲取的,那麼這個地址是啥呢?通過查詢合約,我們得到了ETH代幣對應的resourceID的代幣合約地址是0x0000000000000000000000000000000000000000
哎,這裡就有同學想來問啦,0地址不就是沒有設置過的意思嗎?為什麼一個沒有設置過的地址能通過檢查呢?於是我們就不死心的去查這個地址是不是真的是在白名單裡,結果一查,哎?結果還真是,芭比Q了
為什麼會有這個操作呢?回顧剛才的代碼,由於QBirdgeHandler的depositETH函數同樣是包含白名單檢查的,但是充值native ETH它沒有代幣合約哇,怎麼做白名單檢查呢? QBridge採用了一個大多數項目都會採用的辦法,那就是如果你充值的是native ETH代幣,那麼我在合約裡就當你是充值0 地址的代幣,也就是說,你充值0 地址的代幣,就認為你充的是ETH啦。
那第二個問題來啦,0 地址的調用是怎麼成功的?哎?這就是一個有趣的問題啦,我們知道,0地址其實是一個EOA地址,那麼EOA地址中是沒有合約代碼的,那麼在evm的實現中,對EOA地址的調用是不會報錯的,同時也不會執行任何操作。一個老trick:D, 這個trick在19年的0x protocol 上出現過
也就是說, 0 地址直接就成功調用safeTransferFrom函數而沒有報錯啦,但是,handler的檢查和調用結束後,對應的在QBridge合約聲明出來的event,卻是和轉入了ETH是一模一樣的哦。但是relayer哪知道這麼多,它只是一個執行event捕獲的雲服務器而已:D
總結
這次Qubit Fiance的被黑其實同時存在了好幾個問題
最大的問題,自然是EOA調用的問題,其實是不會報錯的,這個問題沒有被意識到
但是除了這個問題之外,還需要結合depositETH和deposit函數本身聲明的是同一個類型的事件,不然也是不會出問題的
彩蛋
經過查詢,deposit函數以前是用來充值WETH的,而且用的resourceID和這次攻擊用的ID是一樣的,那麼以前的調用是正常的,那麼為什麼現在就不正常呢?肯定是有人改過嘛:D
然後果不其然,我還真的找到了
而這個函數,只有owner才能調用,為什麼要這樣搞呢?細節請大家發揮聯想,我的分析之旅到這裡就結束了;)