How to pass GatekeeperOne in Solidity 0.5

Hi!
I am at the end of updating Ethernaut to Solidity to 0.5. But I need some help with GatekeeperOne level - I have a problem with testing and I can’t pass this level in the new version.

There is a code:
GatekeeperOne.sol

    pragma solidity ^0.5.0;

    import 'openzeppelin-solidity/contracts/math/SafeMath.sol';

    contract GatekeeperOne {

      using SafeMath for uint256;
      address public entrant;

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

      modifier gateTwo() {
    require(gasleft().mod(8191) == 0);
    _;
      }

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

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

I can pass GateOne and GateTwo (in Remix) but have a problem with GateThree.
I will be grateful for your support :slight_smile:

2 Likes

Hi @paulinablaszk

Thanks for all the hardwork on updating Ethernaut.

Have you tried upgrading GatekeeperOneAttack.sol?

I haven’t managed to upgrade the following line yet to try it out.

      if (address(GatekeeperOneContractAddress).call.gas(i + 150 + 8191 * 3)(

I wonder if the changes in Solidity from 0.4 to 0.5 are reducing/removing some of the attack for this level.

1 Like

Yes, I was trying to update GatekeeperOneAttack.sol .
The line:
if (address(GatekeeperOneContractAddress).call.gas(i + 150 + 8191 * 3)(
is fine - if you comment gateThree modifier in GatekeeperOne.sol all tests will pass

1 Like

Hi @paulinablaszk

The issue appears to be with the bytes conversion in gate 3 which is added as part of the upgrade to Solidity 0.5:

uint32(bytes4(_gateKey))
uint16(bytes2(_gateKey))

I emitted an event with the values to compare:

Solidity 0.4

txOrigin: 0x627306090abab3a6e1400e9345bc60c78a8bef57 
gateKey: 0x000000010000ef57 
gateKeyUint32: 61271 
gateKeyUint16: 61271 
gateKeyUint64: 4295028567 
txOriginUint16: 61271

Solidity 0.5

txOrigin: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
gateKey: 0x000000010000ef57 (bytes8)
gateKeyUint32: 1 (uint32) 
gateKeyUint16: 0 (uint16) 
gateKeyUint64: 4295028567 (uint64) 
txOriginUint16: 61271 (uint16)

Next step is to work out if and how we can do this conversion.

2 Likes

Thank you @abcoathup! so now we are step closer :slight_smile: This is the last test which has been left to finish Solidity 0.5 update…

1 Like

Hi @paulinablaszk

Very excited that this is the last test to finish the Solidity 0.5 update! :fireworks:

I found the answer in the Solidity documentation:

https://solidity.readthedocs.io/en/v0.5.10/050-breaking-changes.html

  • Conversions between bytesX and uintY of different size are now disallowed due to bytesX padding on the right and uintY padding on the left which may cause unexpected conversion results. The size must now be adjusted within the type before the conversion. For example, you can convert a bytes4 (4 bytes) to a uint64 (8 bytes) by first converting the bytes4 variable to bytes8 and then to uint64 . You get the opposite padding when converting through uint32 .

The gateThree modifier can be updated to first convert bytes8 to uint64 and then to the required uintY size.

    modifier gateThree(bytes8 _gateKey) {
        require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
        require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
        require(uint32(uint64(_gateKey)) == uint16(tx.origin), "GatekeeperOne: invalid gateThree part three");
        _;
    }
1 Like

Hi @abcoathup cool! Thank you very much! :tada::tada::tada:
I have pushed changes on github. But I am still not 100% sure if all of “museum levels” are unsolvable :wink:

1 Like

Fantastic.

Have you got an example of a museum level that you are concerned about?

Let me know if I can help with any of the levels.

They are in my PR description:

“MUSEUM” ?

  • Fallout - ( constructor )
  • Elevator ( staticcall )
  • Locked - ( memory modifier added to struct inside register function)
  • Alien Codex -(The ABI decoder reverts in the beginning of functions if passed calldata is too short or points out of bounds?)

Fallout is rather obvious here

1 Like