> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfwriteup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/quillctf/true-xor.md).

# 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:

```solidity
    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:

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

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

<figure><img src="https://223316867-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVtlSxURaW2QQu6RU5%2Fuploads%2FCyIFzogxOqkWprZD8PmW%2Fimage.png?alt=media&amp;token=f658ff4f-a0a4-4125-8a6b-7bd92282310c" alt=""><figcaption></figcaption></figure>

## PoC

{% embed url="<https://github.com/ret2basic/QuillCTF-PoC/blob/main/TrueXOR/test/TrueXOR.t.sol>" %}
TrueXOR PoC
{% endembed %}
