True XOR

Idea

To pass the require(msg.sender == tx.origin) check, use vm.prank(msg.sender) in the PoC test case.

For boolean p and q we have to provide a true and a false. The naive idea will be use a storage variable counter to distinguish the first call and the second call. However it does not work because giveBool() must be a view function, which can not modify storage variables.

Here is an interesting observation is that:

    bool p = IBoolGiver(target).giveBool(); // more gas left
    bool q = IBoolGiver(target).giveBool(); // less gas left

There must be a difference between the gasleft() after the first call and after the second call. We can utilize this difference and provide different booleans.

For easier debugging, we can send only a small amount of gas when calling callMe() and record the gasleft() after the first call and the second call. For example, sending 10000 gas works:

trueXOR.callMe{gas: 10000}(address(attackContract));

In my debugging session the first gasleft() is always larger than 6000:

PoC

Last updated