blockchains-security-toolkit/advanced_expert/vulnerabilities/reentrancy_attacks
2024-11-04 18:42:30 +07:00
..
README.md organize chapters for the ongoing research, remove dead links, add new resources 2024-11-04 18:42:30 +07:00
reentrancy.sol Create reentrancy.sol 2023-06-19 09:09:23 -07:00

reentrancy attacks


tl; dr

  • when a contract calls an external function, that external function may itself call the calling function.
  • a reentrancy attack may occur when:
    • a function makes an external call to a untrusted contract
    • the unstrusted contract makes a recursive callback to a vulnerable contract function to steal funds
  • to prevent this attack, a contract can implement a lock in storage that prevents re-entrant calls.
  • bt3gl's diagram:



example


for example, suppose this method:

function withdrawBalance() public {
      uint amountToWithdraw = userBalances[msg.sender];
      (bool success, ) = msg.sender.call.value(amountToWithdraw)("");
      requires(success);
      userBalances[msg.sender] = 0;
}

and this exploit:

function() public payable {
      if(msg.sender == address(vulnContract)) {
        vulnContract.withdrawBalance();
      }
}

how to fix?


option 1: Adding a mutex locking:

modifier noReentrant() {
  require(!locked, "nooooope");
  locked = true;
  _;
  locked = false;
}

so

function withdrawBalance() public noReentrant {
    ...
}

option 2: CEI (checks effects interaction) pattern



function withdrawBalance() public {
    uint amountToWithdraw = userBalances[msg.sender];
    userBalances[msg.sender] = 0; // update state first
    (bool success, ) = msg.sender.call.value(amountToWithdraw)("");
    requires(success);
}


cool resources