By:kong
背景
從DeFi 之夏到現在,我們在遭受各種漏洞、後門、跑路等層出不窮的手段洗禮後,總算學會了在DEX 上參與新項目前,應先檢查代幣合約的權限、代幣的持倉分佈及合約的代碼以保護自己的資產安全。但相對的,壞人們的作惡手段也更加高明與隱蔽。近期,慢霧安全團隊收到來自PancakeSwap 社區用戶的求助,其參與項目時觀察到,在項目代幣沒有任何增發記錄的情況下,惡意用戶使用未被記錄的大量增發代幣捲走了池子中的資金。慢霧安全團隊跟進分析此事件並將結果分享如下:
攻擊細節
惡意代幣IEGT 在BSC 上的部署地址是0x8D07f605926837Ea0F9E1e24DbA0Fb348cb3E97D[1]。我們通過區塊瀏覽器觀察其Holders,發現在dead 與pair 地址持有大量IEGT 代幣的情況下,合約記錄的totalSupply 仍為5,000,000。
通過進一步查看這些代幣的來源可以發現,這些代幣在0x00002b9b0748d575CB21De3caE868Ed19a7B5B56 中只有轉出記錄而沒有轉入記錄。
我們都知道,EIP20標準[2]規定了代幣轉移時必須實現Transfer 事件,包括在代幣鑄造時,從0x0 地址進行轉移也必須進行事件記錄。區塊瀏覽器依賴這些標準的事件記錄進行數據統計。因此,當在區塊瀏覽器中發現其代幣總額與實際數量不匹配時,則表明代幣在進行增發時並未進行事件記錄,導致區塊瀏覽器只統計了轉賬後相關地址的餘額變化,而沒有任何代幣增發記錄。據此,我們可以確定代幣合約中必然存在增發代幣的惡意代碼。
此代幣合約的代碼是開源的,想來是項目方為了增加項目的可信度。接下來我們對其源碼進行分析。一般來說,進行代幣增發最簡單的方式就是實現一個直接增加指定地址餘額的方法。在當前合約中是通過定義一個_balances 映射,對用戶的代幣餘額進行記錄。但經過檢查,合約中並未實現對指定地址的_balances 進行修改的代碼。
既然沒有發現直接增加餘額的代碼,那麼項目方又是如何進行增發的呢?我們回顧下智能合約的基礎知識,可以知道用戶代幣餘額的變化本質上就是修改了合約在鏈上存儲的數據狀態。因此,只要修改特定地址的_balances 在合約中對應存儲的插槽數據,即可修改其代幣餘額。
我們先簡單回顧下EVM 中計算合約數據存儲位置的基礎知識,對於映射類型_balances 來說,其會根據其鍵值k 與其所佔據位置p 進行keccak256 後得到偏移量,作為其存儲的插槽位置,即keccak256(k,p)。通過分析IEGT 合約的數據存儲位置,我們可以發現其_balances 參數所在位置為slot0,那麼用戶的餘額存儲位置即為keccak256(address,0) 。
帶入惡意地址進行計算,可以得到其餘額存儲位置為0x9d1f25384689385576b577f0f3bf1fa04b6829457a3e65965ad8e59bd165a716。隨後查找此插槽數據變化,可以發現其在合約部署時已被修改為一個巨大的值。
因此,我們可以確定在IEGT 合約部署初始化時,項目方就隱蔽地增發了大量的代幣,為Rug 做好準備。接下來我們跟進其初始化函數,分析發現其在進行_pathSet 操作時,通過內聯彙編對合約存儲進行了修改,並且未對代碼進行格式化處理,以降低其可讀性。
跟進計算發現y 值為2b9b0748d575cb21de3cae868ed19a7b5b56,通過兩次mstore 將內存0~64 字節的位置填充為00000000000000000000000000002b9b0748d575cb21de3cae868ed19a7b5b56,而惡意增加代幣餘額的地址為0x00002b9b0748d575CB21De3caE868Ed19a7B5B56。可以發現惡意用戶通過構造一連串的數據,計算使得正好可以得到其控制的目標地址。因此,我們也可以從編譯後的字節碼中發現此計算後未進行填充的“地址”。
緊接著通過keccak256 對內存0~64 字節的數據進行哈希後,正好得到惡意用戶的餘額存儲插槽位置0x9d1f25384689385576b577f0f3bf1fa04b6829457a3e65965ad8e59bd165a716,這也正是合約中將_balances 置於slot0 位置的原因,這極大方便了在內聯彙編中計算餘額實際的存儲位置。然後使用sstore 將合約中此存儲位置的值修改為當前時間的6 次方,此時即完成了對指定地址的餘額修改。隨後的內聯彙編操作類似,在此不做贅述。
至此,我們知道了項目方是在合約初始化時,通過內聯彙編的方式修改了指定地址餘額,隱蔽地增發了大量未被其他用戶獲悉的代幣,導致用戶在參與項目時被Rug。
追踪分析
通過MistTrack[3]分析此次事件獲利地址為BSC 鏈上0x000000481F40f88742399A627Cbc2Afb6Ec34FeD 與0x00002b9b0748d575CB21De3caE868Ed19a7B5B56,共計獲利114 萬USDT,獲利地址轉移USDT 的手續費來源為Binance 交易所提款。
目前資金轉移情況如下圖:
此外,惡意合約創建者的手續費地址0xb795ad917DAF9A1c98eE18E03E81FBBfb6D54355 同樣存在大量痕跡。
總結
此次事件中,項目方開源合約代碼以增加用戶信任度,通過未格式化的代碼降低代碼可讀性,並且使用內聯彙編來編寫直接修改用戶餘額存儲插槽數據的代碼,提高了代碼分析門檻。其使用種種手段隱藏作惡痕跡,最後將池子席捲一空。可以發現,在用戶的安全意識越來越強的情況下,作惡者的手段也越發隱蔽與高明。據SlowMist Hacked[4] 統計,截止目前,由於Rug Pull 導致的損失金額接近5 億美元。因此,用戶在參與新項目時應著重分析其合約中是否存在可疑的代碼,盡量不參與合約未開源且未經過審計的項目。 MistTrack 團隊也將持續跟進並監控此事件。
參考鏈接:
[1]https://bscscan.com/address/0x8d07f605926837ea0f9e1e24dba0fb348cb3e97d
[2] https://eips.ethereum.org/EIPS/eip-20
[3]https://misttrack.io/
[4] https://hacked.slowmist.io/