總覽
本文從源代碼層面對Solidity編譯器(0.5.8<=version<0.8.16)在ABIReencoding過程中,由于對固定長度的uint和bytes32類型數組的錯誤處理所導致的漏洞問題進行詳細分析,并提出相關的解決方案及規避措施。
漏洞詳情
ABI編碼格式是用在用戶或合約對合約進行函數調用,傳遞參數時的標準編碼方式。具體可以參考Solidity官方關于ABI編碼的詳細表述。
在合約開發過程中,會從用戶或其他合約傳來的calldata數據中,獲取需要的數據,之后可能會將獲取的數據進行轉發或emit等操作。限于evm虛擬機的所有opcode操作都是基于memory、stack和storage,所以在Solidity中,涉及到需要對數據進行ABI編碼的操作,都會將calldata中的數據根據新的順序按照ABI格式進行編碼,并存儲到memory中。
該過程本身并沒有大的邏輯問題,但是當和Solidity的cleanup機制結合時,由于Solidity編譯器代碼本身的疏漏,就導致了漏洞的存在。
根據ABI編碼規則,在去掉函數選擇符之后,ABI編碼的數據分為head和tail兩部分。當數據格式為固定長度的uint或bytes32數組時,ABI會將該類型的數據都存儲在head部分。而Solidity對memory中cleanup機制的實現是在當前索引的內存被使用后,將下一個索引的內存置空,以防止下一索引的內存使用時被臟數據影響。并且,當Solidity對一組參數數據進行ABI編碼時,是按照從左到右的順序進行編碼!!
數據:自FTX事件后,Solana平均每日鏈上流動價值下降96%:12月8日消息,據Delphi Digital數據,今年10月初,Solana平均每日鏈上流動總價值為329億美元,而自FTX崩潰后,該數據大幅下降,至今平均每日鏈上流動價值為14億美元,下降了96%。[2022/12/8 21:29:35]
為了便于后面的漏洞原理探索,考慮如下形式的合約代碼:
contractEocene{
eventVerifyABI(bytes,uint);
functionverifyABI(bytescalldataa,uintcalldatab)public{
emitVerifyABI(a,b);//Event數據會按照ABI格式編碼之后存儲到鏈上
}
}
合約Eocene中verifyABI函數的作用,僅僅是將函數參數中的不定長bytesa和定長uintb進行emit。
這里需要注意,event事件也會觸發ABI編碼。這里參數a,b會編碼成ABI格式后再存儲到鏈上。
我們使用v0.8.14版本的Solidity對合約代碼進行編譯,通過remix進行部署,并傳入verifyABI(,)。
首先,我們看一看對verifyABI(,)的正確編碼格式:
0x52cd1a9c//bytes4(sha3("verify(btyes,uint)"))
數據:灰度增持SOL和FIL:根據Tokenview鏈上數據顯示,灰度今日增持592枚SOL,6439枚FIL。當前灰度總持倉量達317.71億美元。[2022/1/25 9:11:24]
0000000000000000000000000000000000000000000000000000000000000060//indexofa
0000000000000000000000000000000000000000000000000000000000011111//b
0000000000000000000000000000000000000000000000000000000000022222//b
0000000000000000000000000000000000000000000000000000000000000002//lengthofa
0000000000000000000000000000000000000000000000000000000000000040//indexofa
0000000000000000000000000000000000000000000000000000000000000080//indexofa
0000000000000000000000000000000000000000000000000000000000000003//lengthofa
Solana:正在與交易所合作解決Solana相關資產存取款問題:Solana在推特上表示:“我們注意到,由于最近的網絡升級,一些交易所在Solana相關資產的存取款方面遇到了一些問題,我們正與交易所密切合作解決這一問題,希望能很快得到解決。”[2021/8/27 22:41:46]
aaaaaa0000000000000000000000000000000000000000000000000000000000//a
0000000000000000000000000000000000000000000000000000000000000003//lengthofa
bbbbbb0000000000000000000000000000000000000000000000000000000000//a
如果Solidity編譯器正常,當參數a,b被event事件記錄到鏈上時,數據格式應該和我們發送的一樣。讓我們實際調用合約試試看,并對鏈上的log進行查看,如果想自己對比,可以查看該TX。
成功調用后,合約event事件記錄如下:
!!震驚,緊跟b的,存儲a參數長度的值被錯誤的刪除了!!
0000000000000000000000000000000000000000000000000000000000000060//indexofa
0000000000000000000000000000000000000000000000000000000000011111//b
Solana鏈上去中心化交易所Saber鎖倉量突破4億美元:數據顯示,基于Solana的去中心化交易所Saber總鎖倉量(TVL)已突破4億美元。Saber表示,TVL在兩天時間里從2億美元增至3億美元,在一天時間里就從3億美元增至4億美元。
據此前報道,基于Solana的跨鏈穩定幣交易所Saber Labs獲得770萬美元種子輪融資,Race Capital領投,Social Capital、Jump Capital、Multicoin Capital、Solana Foundation、Jason Lau(OKCoin)、Tristan Yver(FTX)、Julien Bouteloup(Curve Finance)、Jeff Kuan(Terraform Labs)以及Ryan Shea(Stacks)等參投。此輪融資將用于招聘、營銷、業務產品開發等三個領域。[2021/8/19 22:24:10]
0000000000000000000000000000000000000000000000000000000000022222//b
0000000000000000000000000000000000000000000000000000000000000000//lengthofa??whybecome0??
0000000000000000000000000000000000000000000000000000000000000040//indexofa
Solana域名上線至今已完成4954起拍賣,最高競價達5500USDC:Solana域名服務上線時間已三周,總共完成拍賣4954起,目前域名”square.sol\"和”starbucks.sol\"獲得最高競價5,500 USDC。 Solana域名服務現支持英文,簡體中文,繁體中文,表情注冊域名。該服務由Solana鏈上頭部項目Bonfida提供,Solana域名服務收到的所有USDC都會用來回購和銷毀FIDA(Bonfida項目通證)。
Solana域名服務旨在提供一種去中心化和可承擔的方式,將域名(.sol)和鏈上數據連接起來。這些鏈上數據可以是SOL地址、IPFS的內容ID、圖片、文本、或者任何其它的東西。域名服務一個很明確的優勢是可以與SOL地址映射,便于人們讀取,并替代使用SOL地址進行鏈上轉賬與支付。[2021/7/16 0:57:39]
0000000000000000000000000000000000000000000000000000000000000080//indexofa
0000000000000000000000000000000000000000000000000000000000000003//lengthofa
aaaaaa0000000000000000000000000000000000000000000000000000000000//a
0000000000000000000000000000000000000000000000000000000000000003//lengthofa
bbbbbb0000000000000000000000000000000000000000000000000000000000//a
為什么會這樣?
正如我們前面所說,在Solidity遇到需要進行ABI編碼的系列參數時,參數的生成順序是從左至,具體對a,b的編碼邏輯如下
Solidity先對a進行ABI編碼,按照編碼規則,a的索引放在頭部,a的元素長度以及元素具體值均存放在尾部。
處理b數據,因為b數據類型為uint格式,所以數據具體值被存放在head部分。但是,由于Solidity自身的cleanup機制,在內存中存放了b之后,將b數據所在的后一個內存地址(被用于存放a元素長度的內存地址)的值置0。
ABI編碼操作結束,錯誤編碼的數據存儲到了鏈上,SOL-2022-6漏洞出現。
在源代碼層面,具體的錯誤邏輯也很明顯,當需要從calldata獲取定長bytes32或uint數組數據到memory中時,Solidity總是會在數據復制完畢后,將后一個內存索引數據置為0。又由于ABI編碼存在head和tail兩部分,且編碼順序也是從左至右,就導致了漏洞的存在。
具體漏洞的Solidity編譯代碼如下:
當源數據存儲位置為Calldata,且源數據類型為ByteArray,String,或者源數組基礎類型為uint或bytes32時進入ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup()
進入之后,會首先通過fromArrayType.isDynamicallySized()對源數據是否為定長數組來對源數據進行判斷,只有定長數組才符合漏洞觸發條件。
將isByteArrayOrString()判斷結果傳遞給YulUtilFunctions::copyToMemoryFunction(),根據判斷結果來確定是否在calldatacopy操作完成后,對后一個索引位置進行cleanup。
上訴幾個約束條件結合,就只有位于calldata中的源數據格式為定長的uint或bytes32的數組復制到內存時才能觸發漏洞。也即是漏洞觸發的約束條件產生的原因。
由于ABI進行參數編碼時,總是從左到右的順序,考慮到漏洞的利用條件,我們必須要明白,必須在定長的uint和bytes32數組前,存在動態長度類型的數據被存儲到ABI編碼格式的tail部分,且定長的uint或bytes32數組必須位于待編碼參數的最后一個位置。
原因很明顯,如果定長的數據沒有位于最后一個待編碼參數位置,那么對后一內存位置的置0不會有任何影響,因為下個編碼參數會覆蓋該位置。如果定長數據前面沒有數據需要被存儲到tail部分,那么即便后一內存位置被置0也沒有關系,因為該位置并不背ABI編碼使用。
另外,需要注意的是,所有的隱式或顯示的ABI操作,以及符合格式的所有Tuple,都會受到該漏洞的影響。
具體的涉及到的操作如下:
event
error
abi.encode*
returns//thereturnoffunction
struct//theuserdefinedstruct
allexternalcall
解決方案
當合約代碼中存在上訴受影響的操作時,保證最后一個參數不為定長的uint或bytes32數組
使用不受漏洞影響的Solidity編譯器
尋求專業的安全人員的幫助,對合約進行專業的安全審計
關于我們
AtEoceneResearch,weprovidetheinsightsofintentionsandsecuritybehindeverythingyouknowordon'tknowofblockchain,andempowereveryindividualandorganizationtoanswercomplexquestionswehadn'tevendreamedofbackthen.
Learnmore:Website|Medium|Twitter
Tags:SOLSOLALANAOLAsol幣是什么幣有什么應用solana幣的最新價格solana幣下半年會漲到多少價格Frz Solar System
據官方消息,去中心化超抵押穩定幣USDD現已支持Aptos網絡。用戶可以通過由LayerZero提供支持的TheAptosBridge.com將USDD轉移到Ethereum、BNBChain和.
1900/1/1 0:00:00近日,時代周刊援引韓國媒體報道稱,已有多起自殺事件被認為與加密貨幣交易損失有關。韓比特幣憂郁患者不斷增加,多人或因幣市大跌自殺韓國是全球第三大加密貨幣市場,據韓國今年2月公開報道顯示,人口520.
1900/1/1 0:00:00日前,“孫宇晨美術館”重磅亮相。作為主講人,波場TRON創始人孫宇晨在開箱視頻中向大家介紹了多個頂級藏品.
1900/1/1 0:00:00原文來源:Blockdata 原文編譯:白澤研究院 從SBIHoldings,Inc.談論Web3在金融服務和資產管理方面的未來,到納斯達克推出加密貨幣托管解決方案.
1900/1/1 0:00:00各位朋友,歡迎來到SignalPlus每日晨報。SignalPlus晨報每天為各位更新宏觀市場信息,并分享我們對宏觀趨勢的觀察和看法。歡迎追蹤訂閱,與我們一起關注最新的市場動態.
1900/1/1 0:00:001.2022年市場回顧(MarketsinReview)雖然理由不盡相同,但對于宏觀資產和加密資產而言,2022年都是值得銘記的一年.
1900/1/1 0:00:00