We often hear about major attacks conducted against projects that have failed to get a smart contract audit. You know the story: headlines with eye-watering numbers, a once promising project now relegated to history, the usual narratives peddled about the ‘wild west’ of crypto. Yet for all that, there is strikingly little discussion around the technical nuts and bolts of what went wrong, and how it might be averted in the future.
As a new and rapidly growing technology, vulnerabilities are of course inevitable, and paradoxically they are also essential for increased blockchain security as they push projects to understand potential weaknesses and avoid future attack, both through better preparation, and through simple security measures like having a third party smart contract audit.
With that in mind, this blog post will take you through one of the most infamous exploits in blockchain security: the reentrancy attack.
In simple terms, a reentrancy attack occurs between two smart contracts, where an attacking smart contract exploits the code in a vulnerable contract to drain it of its funds. The exploit works by having the attacking smart contract repeatedly call the withdraw function before the vulnerable smart contract has had time to update the balance.
This is only possible because of the order in which the smart contract is set up to handle transactions, with the vulnerable smart contract first checking the balance, then sending the funds, and then finally updating its balance. The time between sending the funds and updating the balance creates a window in which the attacking smart contract can make another call to withdraw its funds, and so the cycle continues until all the funds are drained.
Put like this it may seem simple, and yet the scale and cost of such reentrancy attacks should be a reminder that you can’t be too safe when it comes to your code, and that a third party smart contract audit should be a staple of any project serious about their smart contract’s security.
Here’s a more granular example:
Let’s call the vulnerable contract, contract A, and the malicious contract, contract B.
An attacker makes a call on contract A to transfer funds to contract B. Receiving the call, contract A first checks to see that the attacker has the funds, then it transfers the funds to contract B. Upon receiving the funds, contract B executes a fallback function which calls back into contract A before it is able to update its balance, thus restarting the process.
Image source: CryptoMarketPool
Let’s take a look at some of the more famous examples that have made reentrancy attacks such a formidable exploit within blockchain security.
Perhaps the most infamous case of a reentrancy attack occurred in 2016 when Ethereum’s DAO (decentralized autonomous organization) was hacked for an equivalent of $60 million dollars in Ether. For those that don’t know, Ethereum’s DAO was a project designed to act as an investor-directed venture capital firm where members in the network could vote on initiatives to invest in.
The DAO raised an incredible $150 million of funds in one of the most successful crowdfunding projects in history. However, from early on, computer scientists and others in the community were expressing concerns that the smart contract in which the funds were locked was vulnerable to a reentrancy attack due to a recursive call bug in the code.
Like any good project in response to problems flagged by a third party opinion (cough smart contract audit cough) the dev team set to work fixing the problem. But not before a hacker was able to conduct the attack themself and drain the smart contract of a whopping 3.6 million ether!
The DAO hack has since become a landmark moment in the history of blockchains, not least because it precipitated the Ethereum hard fork in order to regain the funds, giving birth to Ethereum Classic in the process. It also stands as a real learning moment for blockchain security, with reentrancy vulnerabilities being a staple check in any professional smart contract audit.
Still unconvinced? Well, reentrancy attacks didn’t stop there. Despite crypto security adapting in response to the DAO hack, with smart contract audits and better developer awareness now being staples of any blockchain project worth its salt, unfortunately, hackers adapted their attacks too.
In April 18th 2020, a hacker used a reentrancy attack to steal $25 million from Lendf.me protocol, a decentralized finance protocol designed to support lending operations on the Ethereum platform. The hackers exploited a bug that occurred through the Lendf.me allowing ERC777 tokens– an Ethereum token standard that allows for more complex interactions when trading tokens– to be used as collateral. The developers overlooked that ERC777 tokens contain a callback function that notifies users when money has been sent or received. By having the recipient as a smart contract, hackers were able to exploit this otherwise secure token standard with sophisticated reentrancy attack, draining the Lendf.me platform of 99.5% of its funds.
Ironically, it seems that the hackers used an exploit first highlighted in a smart contract audit by a third party smart contract audit platform, which just goes to show the importance of paying close attention to the concerns of the experts in de-fi security.
Aside from the most effective step of getting a third party smart contract audit on your project, developers looking to defend against reentrancy attacks need to keep a close eye on the structure of their code, particularly around any smart contract that contains callback functions. If a smart contract audit were to highlight a project as being vulnerable to a reentrancy attack, it is likely that they will either recommend restructuring the code so that the balances are updated before the funds are sent, or using a different function to transfer the funds.
As is often the case with blockchain technology, the problems surrounding reentrancy in smart contracts do not originate in blockchain, but rather provide a novel and complex example of them.
Reentrancy is a term that has been present in computing for many years, and simply refers to the process whereby a process can be interrupted mid way through execution, have a different occurrence of the same function begin, then have both processes finish to completion. We use reentrant functions in computing safely everyday. One good example is being able to begin an email draft in a server, exiting it to send another email, then being able to return to the draft to finish and send it.
So that’s a benign case of reentrancy that is simple, useful and not a threat. The problems begin to arise (and smart contract audits need to be brought in) when we shift this example away from a person sending an email, to a smart contract sending money. It’s a classic example of how cryptocurrencies and blockchain technology have upped the stakes of computing, providing some of its most sophisticated applications, whilst also making its pitfalls far more painful. The continued development of blockchain technology and de-fi security is unimaginable without encountering new vulnerabilities, failures, and even hacks. Whilst these pain points are a natural and essential part of any innovation, they also should impel developers and serious blockchain projects to put their code to the test with a smart contract audit before launching. That way, any potential vulnerabilities can serve as useful teachers, rather than catastrophic failures.