英文原文:https://arvanaghi.com/blog/pentesting-ethereum-dapps/
譯文來自安全客,譯者:興趣使然的小胃
鏈接:https://www.anquanke.com/post/id/146602

一、前言

所謂的以太坊(Ethereum)去中心化應用(decentralized application,dApp),指的就是基于共識協議(consensus protocol)交互的應用。在本文中,我們選擇的目標為dApp最常見的某類應用場景:與一個或者多個智能合約(smart contracts)交互的常規Web應用。

當我們通過Web訪問某個dApp時(比如使用MetaMask之類的擴展),我們就可以使用自己的私鑰與網站交互,通過web接口對交易進行簽名。

典型的dApp如下所示,這里我使用了web接口以及包含以太坊錢包的Chrome擴展來購買Cryptokitty(區塊鏈養貓):

當瀏覽器與常規Web應用進行交互時,Web應用可能會與其他內部服務器、數據庫或者云端再次交互。最后在我們看來,整個交互過程非常簡單:

對于dApp,大多數交互過程與之類似,但這里還涉及到第三個元素:所有人都可以公開訪問的智能合約。

與Web應用的某些交互操作涉及到讀寫以太坊區塊鏈上的某個或者多個智能合約。

二、多管齊下

dApp之所以會出現,目的是為了讓最終用戶能更加方便地與智能合約進行交互。但現在并沒有明確的規定,要求我們必須通過dApp的Web接口來與dApp的智能合約交互。由于大家都可以公開訪問智能合約,因此我們可以直接與智能合約交互,不受Web服務器處理邏輯的限制,這些處理邏輯可能會限制我們發起的具體交易。

目前為止,我們可以通過兩種方式進行滲透測試:

  1. 標準的Web應用滲透測試,涉及身份認證、訪問控制以及會話管理等方面技術。
  2. 智能合約審計。

換句話說,我們可以檢查Web應用以及智能合約的處理邏輯,看這兩者中是否存在邏輯錯誤。

由于以太坊中存在modifiers(修改器)特性,因此其實我們還可以挖掘出另一種方式進行滲透測試。

三、Modifiers

在以太坊中,我們可以編寫只能從特定以太坊地址調用才能執行的函數。onlyOwner就是modifier的一個典型實例,如果我們正確實現了onlyOwner,那么只有合約的所有者(owner)才能運行某些函數。

contract mortal {
    /* Define variable owner of the type address */
    address owner;

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function writeData(bytes32 data) public onlyOwner returns (bool success) {
        // will only run if owner sent transaction
    }
    ...
}

雖然我們可以直接與智能合約進行交互,但如果正確實現了類似onlyOwner之類的modifier,我們就無法執行某些函數。然而在處理dApp時,Web服務器基本上都會保存對應特權地址的私鑰數據,并且Web應用總是具備特定邏輯,可以接受用戶在Web端的輸入,然后使用其中某個私鑰來調用智能合約中的某個特權函數。

由于dApp的確可以訪問這些特權以太坊地址,那么第三條滲透測試分支就變成:“我們應該如何才能讓dApp幫我們寫入智能合約中的這些特權函數?”

考慮到這一點,現在我們的攻擊面已經擴展為:

  1. 標準的Web應用評估(身份認證、訪問控制、會話管理)。這個過程可能不涉及到智能合約,只涉及到橫向或者縱向的權限提升、數據庫注入、XSS等。
  2. 智能合約審計。權限問題、向上或者向下溢出、競爭條件等等。
  3. 嘗試通過Web接口偽造智能合約的寫入權限。我們是否能找到一種方式,使Web應用以非預期的方式來與智能合約交互?

我之前寫過一段話,可以用來描述dApp的攻擊面:

想象一下有個普通的Web應用,可能帶有各種安全漏洞。現在,想象一下有一款應用,具備如下特點:

1、從頭開始構建自己的數據庫軟件;

2、將這些數據庫對外開放;

3、有些時候這些數據庫中會存有真金白銀。

這就是以太坊dApp開發者所需要面臨的安全挑戰。

— Brandon Arvanaghi (@arvanaghi) 2018年5月28日

四、使用Burp攔截請求

當我們注冊Cryptokitties賬戶時,Web應用的處理邏輯會從用戶的MetaMask擴展中提取用戶所公開的以太坊地址,隨后,網站會要求我們輸入郵箱地址以及賬戶昵稱。

接下來這一步比較重要:由于dApps面向以太坊賬戶,因此基于的是公鑰認證機制,而非密碼認證機制。

因此,Cryptokitties會要求我們簽名某條消息(“Cryptokitties”),確保我們擁有與該地址對應的私鑰。

如果我們攔截這個請求,可以看到如下數據:

從理論上來講,Cryptokitties會驗證sign參數中的數據(即已簽名的“Cryptokitties”消息)是否與address參數中的數據(即我們的以太坊地址)對應。

這個驗證過程位于Web應用的處理邏輯中。我之前碰到過有些dApp沒有正確處理簽名驗證過程,因此我可以將請求中的以太坊地址替換成與簽名不匹配的以太坊地址,如下所示:

Cryptokitties可以正確處理簽名驗證邏輯,但如果某個dApp無法做到這一點,我就可以通過偽造的以太坊地址發起拒絕服務攻擊,也可以在該應用上偽造賬戶身份。

五、登錄過程

Bloom是最為高級的dApp之一,我們可以利用其創建一個去中心化的身份標識。背后的原理就是將身份標識與用戶的以太坊地址綁定,這樣就不會像社會安全碼(SSN)那樣被竊取或者偽造。由于Bloom是迄今為止最為成熟的dApp之一,因此我向大家隆重推薦這款應用,如果大家還沒有創建自己的BloomID,可以考慮嘗試一下。

Bloom在認證處理方面非常嚴格。注冊賬戶后,后續過程中如果我們需要從以太坊地址進行登錄,都需要簽名一條消息,該消息中包含用戶的意圖(我正在登錄)、郵箱地址以及當前時間。

Bloom為什么考慮對這些字段進行簽名?原因有以下幾點:

1、操作意圖:如果用戶不了解他們所簽名的具體內容,那么簽名以及發送簽名數據有時候是比較危險的操作。Bloom在消息文本中明確給出了簽名操作的具體意圖。

2、郵箱地址:Bloom會從簽名中恢復郵箱地址,檢查該地址是否為簽署消息的以太坊地址的注冊郵箱。如果兩者匹配,則此次登錄為有效登錄操作(在當前登錄環節)。

3、時間戳:用來阻止重放攻擊。如果簽名中未包含當前時間信息,獲得該簽名數據的攻擊者可以隨時重放這些數據,以目標用戶的身份進行認證。成功簽名后,如果Web應用在幾分鐘的時間窗口內收到簽名數據,Bloom會認為這個簽名為有效簽名。

如果任何一個字段被篡改,就會出現錯誤信息,這表明Bloom在認證機制方法處理得很好。

六、智能合約漏洞

前面我們討論了智能合約的某種攻擊方式,直接分析了智能合約中是否存在安全漏洞。接下來我們來看一下現實環境中已挖掘出的某些漏洞。

batchOverflow

這個漏洞稱之為batchOverflow漏洞,從名字中我們不難猜到這是一個溢出漏洞。

我發起了一次小測試,想看看大家是否有解決這個溢出漏洞的方法。在查看答案之前,大家可以試一下自己能否找到利用該漏洞的具體方法。

大家可以訪問此鏈接查看詳細分析過程。

重新初始化錢包所有者

我不會把這個漏洞歸為“黑客攻擊”范疇,但Parity的確因為沒有正確實現某個modifier(我們前面分析過這方面內容)而損失慘重。此時任何人都可以調用initWallet函數,將自己的地址設置為該錢包的所有者。

通常情況下,錢包(或者合約)的所有者需要在合約的構造函數中進行設置,構造函數只會被調用一次。如果后續想修改該地址,就需要在某個函數的處理邏輯中進行操作,而該函數需要原先所有者的簽名數據。這種情況下,由于不存在這類modifier,因此攻擊者可以隨時調用initWallet。

大家可以訪問此鏈接查看詳細分析過程。

七、智能合約審計工具

在審計智能合約代碼方面,已經存在一些非常強大的開源工具,其中包括Trail of Bits的Manticore以及ConsenSys的Mythril,我會在另一篇文章中詳細介紹這些工具細節。

八、總結

希望閱讀本文后,大家可以更好地理解dApp的攻擊面,也能了解dApp與標準Web應用之間的差異。

如果大家想了解以太坊或者區塊鏈安全方面的更多內容,歡迎關注我的推特,我會經常更新相關內容。


本文經安全客授權發布,轉載請聯系安全客平臺。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/612/