Understanding Re-entrancy in Smart Contracts

Shashank
SolidityScan
Published in
4 min readNov 10, 2022

--

What is Reentrancy?

In a Re-entrancy attack, a malicious contract calls back into the calling contract before the first invocation of the function is finished. This may cause the different invocations of the function to interact in undesirable ways, especially in cases where the function is updating state variables after the external calls.
This may lead to loss of funds, improper value updates, token loss, etc.

Security Threats About Reentrancy:

The reentrancy technique may prove a huge vulnerability for your Solidity smart contracts. It transfers the control flow to an untrusted contract that intends to drain funds. Let us explore it in detail.

A reentrancy attack occurs when a smart contract makes an external call to another smart contract. Additionally, when a smart contract makes the call, the EVM execution flows from the smart contract (that makes the call) to the called contract. Unfortunately, if the smart contract makes a call to an untrusted contract, a catastrophic risk exists. The called smart contract brings detrimental results; it drains the contract’s funds and creeps into your code.

Also, the untrusted contract could make a reenter call to the elementary smart contract to misuse its vulnerabilities.

A simple example is when a smart contract performs internal accounting with a balance variable and discloses a withdraw function. If the initial contract transfers funds before setting the balance to zero, the latter opens the gate to a reentrancy attack and drains the whole contract.

Example 1

function withdraw() external {
uint256 amount = balances[msg.sender];
require(msg.sender.call.value(amount)());
balances[msg.sender] = 0;
}

The attacker exploits this function to map some balance to their smart contract address and create a fallback function that calls withdraw.

When msg.sender.call.value(amount)()transfers the valid amount, the fallback function calls withdraw function repeatedly, transferring all the funds before balances[msg.sender=0] terminates the transfer. This continues until all the funds are exploited.

DAO Hack — Case Scenario

The DAO hack is a popular reentrancy attack in the history of Ethereum, where the hacker withdrew ether worth 3.6 million in 2016.

The DAO smart contract had a transfer mechanism to transfer ETH to an external address before updating the internal state. The attackers exploited the vulnerable ‘splitDAO’ function to recursively transfer more funds than they were eligible to.

Best Coding Practices to Prevent Reentrancy Attacks and Ensure Smart Contract Security

The best coding practices to ensure blockchain security are:
send, transfer, and call: These functions are actively involved in the reentrancy attacks. It is important to understand how these functions vary from each other. The send and transfer functions are almost similar;
however, transfer reverts when the transaction fails while send does not.

// transfer will revert if the transaction fails
address(receiver).transfer(amount);
// send will not revert if the transaction fails
address(receiver).send(amount);

Both send and transfer have gas limits of 2300 units. The gas limit prevents recursive functions call to the origin function. Unfortunately, the call function does not have a specified gas limit, which makes it more
vulnerable to reentrancy attacks. It forwards its gas to run multi-contract transactions. Always use send or transfer instead of call to prevent security breaches.

Checks, Effects, Interactions
The CEI pattern reveals the order in which you should arrange your functions. Checks point out the facticity of the conditions. Effects point out the state modifications that are the outcomes of interactions. Interactions refer to the transactions executed between contracts/functions.

assert and require statements perform checks when a function begins. Next, the function resolves all the effects of the contract’s state. Finally, the function interacts with other contracts. Since the external functions are called at the last, the state of the contract is not maltreated even if the attackers attempt to make a recursive call to the victim function.

The code in example 1 can be rewritten as follows using the CEI pattern.

Example 2

function withdraw() external {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0;
require(msg.sender.call.value(amount)());
}

Mutex: Mutex (mutually exclusive flag) is a Boolean lock placed on the contract state. The original state of “locked” is false. However, it changes to true before the execution of the vulnerable function and goes
back to false after it ends.

Our product, SolidityScan, can detect Re-entrancy vulnerabilities along with 130+ other vulnerability patterns.

Re-entrancy in Smart Contracts

Conclusion
A successful reentrancy attack is disastrous and may empty all the funds from the origin contract. It is essential to be cognizant of the potential threats and deploy safe solutions.

SolidityScan is an advanced smart-contract scanning tool that discovers vulnerabilities and reduces risks in code. Request a security audit with us, and we will help you secure your smart contracts. Signup for a free trial at https://solidityscan.com/signup

--

--