> 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/weth10.md).

# WETH10

## Idea

```solidity
    function execute(address receiver, uint256 amount, bytes calldata data) external nonReentrant {
        uint256 prevBalance = address(this).balance;
        Address.functionCallWithValue(receiver, data, amount);

        require(address(this).balance >= prevBalance, "flash loan not returned");
    }
```

`execute()` is basically RCE but we only can do limited things with it. The weth pool has 10 ETH and 0 WETH at the beginning and there is no way to convert ETH to WETH then `transferFrom()` all the WETH to us.

```solidity
    function withdrawAll() external nonReentrant {
        Address.sendValue(payable(msg.sender), balanceOf(msg.sender));
        // @audit-issue _burnAll() = _burn(msg.sender, balanceOf(msg.sender));
        // @audit-issue We can transfer WETH out in `fallback()` so that `balanceOf(msg.sender) == 0`
        // @audit-issue Therefore no WETH will be burnt
        _burnAll();
    }
```

```solidity
    function _burnAll() internal {
        _burn(msg.sender, balanceOf(msg.sender));
    }
```

This is similar to a reentrancy attack (but not exact): we let `sendValue()` trigger the callback in our `fallback`/`receive` function and find a way to let `balanceOf(msg.sender) == 0` in that stage. But how?

To achieve `balanceOf(msg.sender) == 0`, we have to transfer all WETH we have at the moment to somewhere else. Recall that we have RCE via `execute()`, which means we can get max allowance by calling `approve()`. With that privilege, we can "donate" WETH to weth pool during `fallback`/`receive` (so that `balanceOf(msg.sender) == 0`) and take the WETH back via `transferFrom()` since we have max allowance. In the next round, we deposit WETH and repeat above process until the weth pool is completely drained.

## PoC

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