Security

導致 DAO hack 的遞歸是如何創建的?

  • July 1, 2016

我理解,如果 DAO 合約具有向合約 X 發送資金的提款功能 - 合約 X 可能是惡意的,並使用回退功能再次呼叫提款功能。然而 - 在 DAO 合約的情況下,X 是 DAO 的另一個副本,因此它沒有這種惡意行為。

那麼遞歸發送究竟是如何實現的呢?

這是withdrawRewardFor函式中有問題的程式碼行:

   if (!rewardAccount.payOut(_account, reward)) <-- reentrant exploit
        throw;
   paidOut[_account] += reward;

payOut 將呼叫接收payout函式:

function payOut(address _recipient, uint _amount) returns (bool) {
   ..
   if (_recipient.call.value(_amount)()) {
   ..
}

如果_recipient是合約,這將呼叫合約的回退函式。該接收者反過來可以再次呼叫 TheDao 合約。由於withdrawRewardFor沒有防止重入,它再次被允許。這意味著在程式碼被允許繼續使用之前持續支付paidOut[_account] += reward;

更多的乙太坊攻擊:Race-To-Empty 是真正的交易,這是在攻擊前一周寫的,對這種類型的黑客攻擊進行了更詳細的分析,並提出了解決方案。

要回答您的問題,您需要區分契約和提案。

DAO 是一種合約,它編纂了通過****提案提供資金的規則。

提案可以是投資請求,也可以是提取您自己的資金的請求(這稱為拆分提案)。當拆分提案被批准後,它會呼叫 splitDAO API 創建一個子 DAO(子合約)。這個子合約的程式碼確實和原來的 DAO 是一樣的。

splitDAO 函式將請求的資金轉移到子 DAO。但它也呼叫了提案提供的預設函式,表面上是為了處理正在轉移的資金。 而這個函式是在資金劃轉操作之後,資金從DAO的總餘額中扣除之前,使用者餘額設置為零之前呼叫的

遞歸漏洞利用嵌入在這個預設函式中。它再次簡單地呼叫了 splitDAO。

實際上,資金轉移、總餘額減少和使用者餘額歸零應該是原子操作。還可以實施其他方法(鎖、互斥鎖)以確保在執行任何外部使用者提供的程式碼之前完成整個拆分操作。

引用自:https://ethereum.stackexchange.com/questions/6210