Ever since the inception of the decentralized finance (DeFi) field, the world has seen massive improvements brought about to rival legacy financial systems. As you will likely already know, DeFi potentially holds the keys to banking the unbanked and truly democratizing finance. Nevertheless, there are still some speed bumps ahead that could slow the mainstream adoption of decentralized finance solutions. While DeFi is making significant advancements, the same old attack vectors keep haunting us. Today we’ll look at the most prominent ones.
If you want to learn more about DeFi, blockchain, and cryptocurrency in general after reading this article, you should definitely consider enrolling in Ivan on Tech Academy. At Ivan on Tech Academy, you’ll join over 30,000 already enrolled students, and you can watch some of the countless real-life success stories brought about by the Academy through testimonials. Supercharge your crypto career by learning from experts in the field by enrolling in Ivan on Tech Academy!
One of the most devastating attacks smart contract developers need to watch out for is reentrancy attacks. They can both drain your smart contract and worm their way into your code.
Computer scientists have defined a procedure as “reentrant” if their execution “can be interrupted in the middle, re-entered, and both runs can complete without any errors in execution.”
With regards to smart contracts, they can perform function calls to other contracts. These contracts can, in turn, call others, and they can even call back to the original contract. When this happens, we can say that reentrancy has occurred.
So reentrancy on the surface is not a bad thing. Problems only arise when reentrancy puts a smart contract into an inconsistent state. A “state” is consistent when the main invariant holds. In a smart contract, the main invariant could be that the amount of withdrawals does not exceed the contract’s supply of tokens. That must hold true.
A Dysfunctional ATM
Let’s use a dysfunctional bank ATM as an example of reentrancy gone awry. What would happen if an ATM only checked your balance after you removed your card? If the machine kept handing out money until you pulled your card, you could empty it before it noticed your balance had passed the zero mark.
Fortunately for wealthy bankers, ATM’s don’t operate this way. Before you can take out money, it checks your balance. And it rechecks it after you withdraw money to update your balance.
Smart contracts aren’t supposed to hand out more money than what they’re holding either. However, by exploiting reentrancy, hackers can effectively turn a smart contract into a dysfunctional ATM.
External Function Calls
Here’s how they do it. During normal execution, function calls can invoke a function from within the same contract or from a different one. Suppose an attacker can control an untrusted contract and get a vulnerable contract to make an external call to it before resolving its internal accounting. In that case, the attacker can make a recursive call back to the original function. A recursive call is a routine that calls itself directly or indirectly.
And if the vulnerable contract will transfer funds before setting its balance to zero, the attacker can repeatedly call the withdraw function until he’s drained the contract.
Multiple withdrawals are possible because the contract’s state has not changed. The state is still consistent because the attacker’s balance is not zeroed out yet. The vulnerable contract has not realized that the withdrawals exceed the supply, so the attacker can pay himself repeatedly until the execution runs out of gas. Do you want to learn more about DeFi Attack Vectors? If so, you should join Ivan on Tech Academy today, and get access to dozens of cryptocurrency courses!
Reentrancy attacks depend on unsafe External Calls. And since every call that is not an Internal Call can be classified as an External Call, how do we know which ones are safe?
- a) Locate the External Call
Developers must first determine if there are any External Calls. If they’re only using Internal Calls, then there are no worries. However, they must closely examine the code because External Calls might be lurking in unexpected places (like public fields that are visible to everyone).
- b) Can the Call Be Hooked?
If they do find external calls, then they must determine if an attacker can hook the call. In other words, can the hacker gain control over the call’s execution? Older versions of Solidity are vulnerable to getting hooked, so developers must scrutinize them for DeFi attack vectors.
- c) Transfer Calls
Even if the outside contract is not attacker-controlled, Transfer Calls are vulnerable to getting hooked.
- d) Composability
In the DeFi “Lego-land” of composability, hackers can attack one contract by manipulating a different one. It’s not enough to have their own house in order; developers also must understand the entire DeFi ecosystem to catch exploits coming from the outside.
Two Types of Reentrancy Attacks
Reentrancy Attacks come in two types: Single Function Reentrancy Attacks—which are the easiest to prevent – and the more complex type called Cross Function Reentrancy Attacks. We won’t explore their differences here, but a hacker used the latter in the now infamous DAO hack.
The DAO Hack
Back in June 2016, the DAO suffered a reentrancy attack for 3.6 million ETH. That number would amount to billions of dollars based on today’s ETH prices.
This attack was so massive that the Ethereum Foundation was forced to roll back the hack by executing a hard fork. They were able to do so and rescue investor funds. However, a part of the community claimed this action violated the immutability principle of cryptocurrency. So, they continued using the old chain. And this, ladies and gentlemen, is why we have Ethereum and Ethereum Classic today.
What happened is that the DAO had a vulnerable function that an attacker exploited, using call.value( ) to create a sequence of recursive calls with a proxy smart contract. Each time the proxy smart contract asked for a legitimate withdrawal from the DAO, the transfer would trigger a fallback function. Then the proxy fallback function would ask the DAO for another withdrawal. And so the process continued because the balance of the proxy smart contract was never updated.
Preventing Reentrancy Attacks
Solidity supports three ways to transfer ETH between smart contracts, send( ), transfer( ), and call.value( ).
The main difference is their gas allowance. The transfer( ) and send( ) functions are considered safer because they are limited to 2,300 gas. This gas limit prevents the expensive external calls back to the vulnerable contract. The call( ) function, however, is more vulnerable.
In the DAO hack case, using the functions send( ) or transfer( ) instead of call.value( ) could have stopped the recursive withdrawal calls because of the low gas allowance. Or the contract could have been rewritten so that it updated the user balance before the transfer call.
Since we can’t banish every external call as a DeFi attack vector, here are a few best practices to consider when protecting smart contracts from reentrancy attacks.
- Use send( ) or transfer( ) in place of call( ) whenever possible.
- Mark untrusted functions.
Developers need to identify untrusted functions by naming them. Also, if a function calls another untrusted function, it too should be named “untrusted.”
- Checks-Effects-Interactions Pattern
The checks-effects-interactions pattern is a reliable preventative. It defines the order the functions should follow, like zeroing out the balance before making an external call. This pattern is still vulnerable, though, because of the potential for human error. So here is one more precaution:
Mutex may be necessary when dealing with more complex issues such as cross-function reentrancy attacks. It is a reentrancy guard that causes execution to fail when reentrancy is detected.
A mutex places a lock on the contract state. An attacker can no longer exploit the withdrawal function or use a call to transfer to execute a cross-function reentrancy attack with a lock in place. Developers have to make sure there is a way to release the lock, however. OpenZeppelin has a Mutex called ReentrancyGuard.
To learn more about best practices for ensuring smart contract security, visit Ivan on Tech Academy today.
Arbitrage (Arb), Flash Loan, and Price Oracle Attacks
These three are listed separately, but attackers often use them in combination with each other.
DeFi Attack Vectors – Flash Loan Attacks
Because of the small fees involved in using them, Flash Loans afford nearly anyone the opportunity to instantly access large amounts of capital. The only requirement is that the borrower has to repay the loan within the same block. The time requirement means they have approximately 10 minutes to get everything done. But you would be surprised at what some of these ingenious hackers can accomplish in that short amount of time.
So, for anyone looking to create an arbitrage opportunity, they can merely take out a Flash Loan, move the market temporarily, and profit off a swap between the assets artificially pushed out of equilibrium.
DeFi Attack Vectors Price Oracle Attacks
Reentrancy attacks are old news to developers, but price oracle manipulation often goes under the radar. Hence it’s not surprising that reentrancy attacks have dropped off while price oracle exploits are increasing.
In these cases, attackers create artificial arbitrage opportunities by engaging in a rapid process of borrowing, swapping, and depositing large amounts of tokens. By doing so, they can manipulate the price of an asset on a decentralized exchange (DEX). Because other protocols will also rely on that DEX as a price oracle, they all can become vulnerable to the exploit. Unless a whale is willing to risk his funds, these kinds of exploits would not be possible without Flash Loans.
However, what is a price oracle exactly?
Price oracles are what protocols consult for asset price information. And different protocols can get their price information in different ways. They can get off-chain price data from places like centralized exchanges and bring it on-chain. Or they can stay on-chain and get their prices instantaneously from a DEX like Uniswap.
Each of these solutions has its advantages and disadvantages. Off-chain data reacts slower to volatility, which may or may not be a good thing. And protocols must trust a small group of individuals to push the data on-chain accurately.
On-chain data, on the other hand, is trustless and is always up-to-date. However, attackers wielding Flash Loans can manipulate price data.
Synthetix Oracle Malfunction
Let’s take the Synthetix protocol as an example. Synthetix is a derivatives platform that used to rely solely on an off-chain price feed.
Back in 2019, their feed misquoted the Korean won, and Synthetix posted it on-chain. A trading bot, smelling blood in the water, quickly seized it and nearly made off with a $1 billion profit. Thankfully the trader returned the funds in place of a bug bounty, but this case demonstrates how quickly things can go south with off-chain data.
Conversely, it can be tempting to snatch up the current spot price on Uniswap or another DEX and use that as a feed. And usually, this data is sufficient because arbitrageurs quickly correct any price deviations. However, spot prices can fluctuate wildly for short bursts of time – just enough for a Flash Loan wizard to work his magic.
The Multiple Source Solution
Some developers are under the wrong impression that a single oracle is to blame for price oracle manipulation.
If an arbitrageur manipulates Kyber, then they jump over to Uniswap and so forth. But in reality, anytime a protocol relies on a single price oracle, it’s asking for trouble. The solution isn’t to hop around to different oracles; the answer is to use multiple sources of information, avoid illiquid tokens, and even consider using the Time-Weighted Average Price solutions.
DeFi Attack Vectors – Arbitrage Attacks
Arb attacks can be a bit controversial because people have questioned whether they are attacks or merely a feature of DeFi? Arbitrageurs traditionally serve to keep markets liquid. However, when a whale or an opportunist with an outsized Flash Loan artificially jacks with oracle prices to create an artificial arbitrage opportunity, is that really an attack? Or is it just temporary profit-taking until the DeFi ecosystem hardens?
While some believe this is unethical or even illegal, while others argue that it’s standard market mechanics at work. Whatever you think, DeFi has seen an increase in Flash Loan attacks. We have witnessed Akropolis, Cheese Bank, Harvest Finance, Origin Protocol, and Value DeFi all get hit with them in just the past month.
DeFi Attacks – Conclusion
We have covered the most likely DeFi Attack Vectors in this article, but others are worth mentioning. If you are curious about these, they include techniques such as Front Running and Sandwich Attacks, Timestamp Dependence, DOS With An Unexpected Revert, and Insufficient Gas Griefing, to name a few. Perhaps we will explore these in future articles, but we have covered the most likely attacks for now.
And to be frank, if a protocol gets hacked in the DeFi ecosystem, it’s often because developers did not build it properly. After all, hackers haven’t had to be that creative in 2020. The Pickle Finance hack notwithstanding, most every other hack this year involved a Flash Loan manipulating a price oracle to launch an Arb attack.
The good news, though, is that the system hardens each time it gets hacked, and hopefully, the DeFi community will learn from the mistakes of 2020. Attacks are sure to grow increasingly advanced in the future. That’s why developers need to employ best practices when coding smart contracts, along with conducting ongoing security audits and bug bounties. Otherwise, the Black Hats with the desire to continually develop their technological prowess for ill-gotten gains could continue to outsmart the White Hats. Nevertheless, every hack has made the industry as a whole more resilient, and highlighted the need for technical due diligence. Do you want to learn how to write secure smart contracts yourself? If you plan on becoming a world-class blockchain developer, make sure to join Ivan on Tech Academy today!