在私有以太坊上實現針對ERC20數字貨幣ProxyOverflow漏洞的攻擊

FLy_鵬程萬里發表於2018-07-11

ERC20的ProxyOverflow漏洞造成影響廣泛,本文將對其攻擊方法進行分析,以便於智慧合約釋出者提高自身程式碼安全性以及其他研究人員進行測試。本文選擇傳播廣泛、影響惡劣的SMT漏洞(CVE-2018–10376)作為樣本進行分析,文中所涉及的程式碼截圖均來自於SMT程式碼。由於目前各大交易平臺已經將ERC20協議的數字貨幣交易叫停,本文的釋出不會對這些貨幣帶來直接影響。

1 ERC20貨幣及transferProxy函式

1.1 ERC20貨幣簡介

基於ERC20協議的數字貨幣(以下簡稱為ERC20貨幣)實際上是以太坊上執行的智慧合約,合約中對於每個賬戶擁有的貨幣數目是通過 賬戶地址→貨幣數 的對映關係進行的記錄:

mapping (address => uint256) balances

ERC20貨幣的擁有者要想進行貨幣交易、餘額查詢等操作時,需要向智慧合約對應的地址傳送訊息,宣告呼叫的函式和相應引數。這一訊息將會礦機接收,並執行智慧合約中相應的函式程式碼。在這一過程中,訊息傳送者需要向挖礦成功的礦機支付相應的報酬。這筆報酬在以太坊中被稱作gas,其支付貨幣為以太幣。也就是說,ERC20的貨幣擁有者要想傳送貨幣交易訊息,就需要擁有一定數量的以太幣。

然而,ERC20貨幣擁有者並不一定擁有以太幣。為了滿足他們發起貨幣交易的需求,ERC20 協議提供了transferProxy函式。利用該函式,ERC20貨幣擁有者可以簽署一個交易訊息,並交由擁有以太幣的第三方節點將其傳送到以太坊上。訊息的傳送者會從擁有者那裡獲取一定數量的ERC20貨幣作為其傳送訊息的代理費用。

1.2 transferProxy函式程式碼分析

SMT的transferProxy函式程式碼如下圖所示:


transferProxy函式體

該函式的各個引數解釋如下,該函式程式碼邏輯較為簡單,此處不做贅述。

  • address _from:ERC20 貨幣的擁有者和交易的發起者;
  • address _to:貨幣交易中的接收者;
  • uint256 _value:貨幣交易的數額;
  • uint256 _feeSmt:交易資訊傳送者(即函式中msg.sender)收取的代理費用;
  • uint _v,bytes32 _r,bytes32 _s:交易發起者(即_from)生成的簽名資料。

需注意的是,程式碼215行中的transferAllowed(_from)是transferProxy()執行前必會執行的驗證函式。該函式程式碼如下:

程式碼117行中的exclude為對映結構,僅合約的建立者將為設定為True,其他地址預設均為False。

程式碼118行判定transferEnabled標誌符是否為true,該標誌只能通過enableTransfer函式設定,且該函式只能被合約建立者呼叫,該函式的作用是使得ERC20合約的交易過程可控,這也是SMT等貨幣出現問題時能夠在後續中止交易的原因:


程式碼119-121行對於交易傳送者(即_from)帳號是否被鎖定進行了檢查,lockFlag和locked都只能被合約建立者所控制:


Lock相關操作函式Lock相關操作函式

綜上所述,只有整個合約在允許交易且攻擊者帳號未被鎖定的情況下,攻擊者才能真正呼叫transferProxy函式。在引數處理過程中發生漏洞的原因可參見我們之前的分析文章:《SMT整型溢位漏洞分析筆記》

2 攻擊重現

為了重現攻擊,我們選擇了基於go語言編寫的以太坊客戶端geth進行以太坊私有網路的部署。為了便於實現可程式設計的自動化互動,我們選擇了Web3.py作為與以太坊節點互動的中介軟體。

2.1 漏洞驗證環境的搭建

S1. 從連結頁面下載SMT智慧合約原始碼;

S2. 建立兩臺Linux虛擬機器;

S3. 準備Python執行環境,在兩臺虛擬機器上安裝python3,並利用pip安裝web3、py-solc、hexbytes、attrdict;

S4. 準備合約編譯環境,在兩臺虛擬機器上安裝智慧合約程式碼編譯器solc,參考連結

S5. 在兩臺虛擬機器上搭建以太坊私有網路,可參考連結,其中:

-- 1) 節點1用於釋出SMT合約程式碼,為其建立以太坊賬戶並分配一定數量以太幣,啟動挖礦;

-- 2) 節點2用於部署攻擊程式碼,建立兩個以太坊賬戶,分別作為transferProxy中的from賬戶(轉賬訊息簽署者,記為Signer)和transferProxy呼叫者(即轉賬訊息的傳送者,記為Sender),為Sender分配一定數量以太幣,並啟動挖礦。

2.2 SMT智慧合約釋出

在節點1上,利用deploy_SMT.py指令碼中的程式碼實現SMT智慧合約的一鍵部署。

關於執行前的配置的介紹:

1) sol_path,代表合約程式碼路徑;

2) account,代表用於釋出合約的賬戶,如1.2所示,只有該賬戶才能呼叫部署好的智慧合約函式,進行控制交易開啟和關閉,維護被鎖賬戶列表等操作;

3) pin,用於解鎖account的密碼。

關於執行過程與結果的分析:

1) tx_receipt,該變數用於獲取部署智慧合約(23行)和傳送啟動交易訊息(35行)的結果,當這兩行程式碼被呼叫後,以太坊網路中會發布相應的訊息,只有在下一個區塊被挖掘出來後,tx_receipt才能獲取非空的結果;

2) contract_address,代表該合約被順利部署到以太坊網路後的合約地址,其他節點要想呼叫合約程式碼,需要獲知該地址以便傳送函式呼叫訊息。

合約程式碼部署結果的截圖如下:

合約部署結果截圖

2.3 ProxyOverflow漏洞攻擊

在節點2上,利用test_SMT.py指令碼中的程式碼可實現針對SMT合約的一鍵攻擊。

關於執行前的配置的介紹:

1) contract_address,來自2.2中SMT部署完成後的輸出值;

2) sol_path,代表合約程式碼路徑;

3) signer,交易資訊的簽署者,也將作為呼叫transferProxy時的_from和_to的實參;

4) sender,交易資訊的傳送者,需要擁有一定數量以太坊以支付gas費用;

5) signer_pin,signer的金鑰解鎖口令,以便對交易資訊進行簽名;

6) sender_pin,sender的金鑰解鎖口令,以便解鎖sender賬戶,支付gas費用;

7) value,代表發生交易的金額;

8) fee,代表支付給sender的代理費用;

9) signer_key_path,代表signer的金鑰檔案路徑。

關於執行過程與結果的分析:

1) 30-35行,基於目標智慧合約地址和程式碼,建立智慧合約物件;

2) 37-38行,獲取並列印sender和signer在攻擊前的SMT幣數目;

3) 40-43行,獲取signer現有的nonce的值,並將其擴充為64字元的字串;

4) 46-62行,構建要進行簽名的資料的Hash值,獲取signer的私有金鑰,並對Hash值進行簽名,獲得簽名資料s,r,v;

5) 63-77行,構造transferProxy函式呼叫引數,進行函式呼叫,並獲取交易回執;

6) 79-80行,獲取並列印sender和signer在攻擊後的SMT幣數目。

攻擊結果的截圖如下:

攻擊結果截圖

相關文章