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
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 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!
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
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