Detailed explanation of Ethereum smart contract vulnerabilities: Reentrancy vulnerability

lunaray
3 min readJan 10, 2022

Detailed explanation of Ethereum smart contract vulnerabilities, Welcome to follow us and discuss

Author: hzqd@lunaray security team

0x01 Re-enter the essence

Contract A calls contract B, and contract B recursively calls back the functions in contract A through fallback().

0x02 pre-knowledge

  • <address>.transfer():If the sending fails, it will return to the transaction state, and only pass 2300 Gas for use to prevent re-entry.
  • <address>.send():If the sending fails, it returns false, and only 2300 Gas is passed for calling to prevent reentry.
  • <address>.call():If the sending fails, it returns false, and all available Gas will be passed to the external contract. Fallback() applies;Gas can be restricted by {value: money }, which cannot effectively prevent reentry.<address>.transfer():

payable identifier

  • Add the payable logo to the function to accept Ether and store it in the current contract.

0x03 Vulnerability recurrence

Take the current latest version of Solidity 0.8 as an example:

The EtherStore contract uses the <address>.call{}() function in the transfer function withdraw(),This causes hackers to use the fallback() function to recursively call the withdraw() function, thereby transferring all the money on the EtherStore contract. We will continue to write the attack code for the above contract:

The attack code first creates a constructor to receive the contract address of the vulnerable code, and then writes the attack function: after depositing money, call the reentrant function withdraw(), and then write the fallback() function to recursively call the reentrant function.

We deploy the first contract and deposit 90 Ether into the contract address:

re1

Next, change the account to deploy the second contract. When deploying, we need to pass in the address of the first contract. Then deposit 1 Ether into the contract to attack:

re2

Next, query the balance of the attack contract:

re3

Click getBalance, and find that the contract has 91000000000000000000 wei, which happens to be 90 ether of the original contract plus 1 ether we deposited. The attack is now complete.

0x04 Security Advices

The easiest way to prevent reentry is to use the <address>.call() function instead of the safer functions, such as transfer() and send().

If you must use the call() function, you can choose to lock to prevent reentry:

If you write the attack code as before, when the above function is called from the callback() function for the second time, the require check will not pass. This prevents reentry.

0x05 summary

Security issues in the blockchain field cannot be ignored, which requires developers to always be cautious and develop defensive programming thinking. In particular, functions that call external contracts should generally be regarded as untrustworthy, and various write operations (update state variables, etc.) are placed before the reentrant function.

--

--

lunaray

Lunaray takes a leading position in smart contract auditing and consulting service for blockchain security.