Solidity

呼叫棧攻擊

  • September 12, 2016

如果我的合約有這樣的支付功能

address bossAddress;
address employeeAddress;
uint256 bossSalary;
uint256 employeeSalary;
function payout (){
   if (msg.sender==bossAddress){
           employeeAddress.send(employeeSalary);
           bossAddress.send(bossSalary);
           selfdestruct(bossAddress);
   }
}

那麼,如果我是一個惡意的老闆,我是否可以利用獎金只給老闆發工資?

A) 如果employeeAddress 是一個合約,而bossAddress 是一個普通地址,我是否可以利用callstack 攻擊讓employeeAddress.send(employeeSalary) 上的事務失敗,但繼續執行bossAddress.send(bossSalary)?我想我要問的是兩個發送呼叫是否減少了呼叫堆棧計數,或者只是涉及契約地址的發送呼叫。

B)另一方面,如果員工地址是一個使用大量gas的合約,我可能不需要做任何exploit,因為employeeAddress.send會因為耗盡gas而失敗,那麼老闆應該得到報酬employeeSalary 和 bossSalary,感謝 selfdestruct() 呼叫。

C) 最後一點,有沒有辦法在發送呼叫中指定氣體?如果employeeAddress 實際上是一個契約,這應該可以防止大多數的錯誤。

我只需要驗證我對 gas / callstack 行為的理解是否正確。

呼叫深度攻擊

A. 不會。如果呼叫深度為 1024,employeeAddress.send將失敗。深度保持在 1024 並且bossAddress.send也將失敗。payout當(或其呼叫者,取決於payout呼叫方式)完成時,深度只會減少到 1023 。

B. 是的,這一切聽起來都是正確的,不需要任何呼叫深度操作。

C. 無法為 Solidity 指定 gas .send(),它會將零 gas 轉發給接收者。如果接收者send()想要避免耗盡氣體並接收乙太幣,那麼他們有責任在他們的備份功能中什麼都不做/很少做。


重入攻擊

Soliditysend轉發零氣體,因此不能用於可重入攻擊。

如果合約至少有兩倍bossSalary(例如:bossSalaryemployeeSalary相同),並且老闆首先使用 支付.call,那麼重入攻擊是可能的:

function payout (){
   if (msg.sender==bossAddress){
           bossAddress.call.value(bossSalary)();
           employeeAddress.call.value(employeeSalary)();
           selfdestruct(bossAddress);
   }
}

bossAddress``payout可以有一個備份函式在員工獲得報酬之前第二次呼叫。由於沒有.call檢查任何返回值,employeeAddress.call將失敗,但沒有throw,所以老闆可以保留兩個薪水。

應仔細檢查和處理all.send.call(以及相關.callcode的 , )的返回值。.delegatecall

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