-
Notifications
You must be signed in to change notification settings - Fork 4
13. GatekeeperOne
r1oga edited this page Oct 29, 2022
·
2 revisions
Make it past the gatekeeper one.
- Contract relies on
tx.origin
. - Being able to read the public contract logic teaches how to pass gateTwo and gateThree.
Be careful, conversion of integers and bytes behave differently!
conversion to | uint | bytes |
---|---|---|
shorter type |
left-truncate: uint8(273 = 0000 0001 0001 0001) = 00001 0001 = 17
|
right-truncate: bytes4(0x1111111122222222) = 0x11111111
|
larger type |
left-padded with 0: uint16(17 = 0001 0001) = 0000 0000 0001 0001 = 17
|
right-padded with 0: bytes8(0x11111111) = 0x1111111100000000
|
Masking means using a particular sequence of bits to turn some bits of another sequence "on" or "off" via a bitwise operation.
For example to "mask off" part of a sequence, we perform an AND
bitwise operation with:
-
0
for the bits to mask -
1
for the bits to keep
10101010
AND 00001111
= 00001010
- Pass
gateOne
Deploy an attacker contract that will call the victim contract'senter
function to ensuremsg.sender != tx.origin
. This is similar to what we've accomplished for the Level 4 - Telephone - Pass
gateTwo
We brute force this gate by trying successively lot of different gas values. - Pass
gateThree
Note that we need to pass a 8 bytes longgateKey
. It is then explicitly converted to a 64 bits long integer.-
Part one:
uint32(uint64(_gateKey)) == uint16(uint64(_gateKey))
Of the last 32 bits ofgatekey
, we want to keep the last 16 bits but remove the first 16 bits.
0000 0000 0000 0000 1111 1111 1111 1111 = 0000 FFFF
-
Part two:
uint32(uint64(_gateKey)) != uint64(_gateKey)
We want to keep the first 32 bits of the 64 bits longgateKey
:1111 1111 1111 1111 1111 1111 1111 1111 = ffff ffff
-
We then concatenate both masks:
0xFFFF FFFF 0000 FFFF
-
- Part three:
uint32(uint64(gateKey)) == uint16(tx.origin)
- we need to take
gateKey = tx.origin
- we then apply the mask on tx.origin to ensure part one and two are correct
- we need to take
- Abstain from asserting gas consumption in your smart contracts, as different compiler settings will yield different results.
- Be careful about data corruption when converting data types into different sizes.
- Save gas by not storing unnecessary values.
- Save gas by using appropriate modifiers to get functions calls for free, i.e. external pure or external view function calls are free!
- Save gas by masking values (less operations), rather than typecasting