Deciphering Defi Attacks: A step towards Securing the Future of Decentralized Finance
An in-depth guide to understanding the most incredible yet minacious Defi attacks of 2020 and the significance of Smart Contract Audits
Table of Contents
The year 2020 has undoubtedly been one of the most significant years in the history of Decentralized Finance. As per the stats by Defi Pulse, the total value locked in defi protocols drastically expanded its boundaries from $700 million at the inception of the year to $13.31 billion as of now.
It goes without saying that with so much at stake, defi didn’t just grab the attention of new investors but also the malicious actors in the market.
This is one of the most crucial reasons why 2020 also became the year where the world witnessed some massive attacks on some of the most renowned protocols like bZx, Cheese Bank, Harvest Finance, Value Defi, etc.
While the start of this year saw Defi hacks that wiped out around just $50 million, by December the total funds lost in Defi attacks were $100 million approximately. Yep, the losses doubled.
One of the most astonishing factors in the Defi attacks of 2020 is the fact that some of those are quite startling since they involved a completely new pattern of DeFi attacks.
While the community was quite aware of the attacks like Re-entrancy, manipulating an entire market with Price oracles or Flash loan attacks were something that literally stupefied us initially.
Considering the current scenario of the Defi world, it is quite imperative for us to at least have a basic understanding of such attacks, their patterns, and their repercussions.
Let’s dive in and understand how exactly such attacks wiped out millions from some of the most renowned Defi protocols.
Price Oracle Manipulation
It's almost impossible to discuss the Defi Attacks of 2020 without considering one of the most alarming attacks that this year has witnessed, i.e., the Price Oracle Manipulation.
Although we quite clearly understand the fact that in order to execute adequately smart contracts profoundly rely on accurate data, truth be told, getting that accurate data with utmost security and reliability is still an enormous concern for the decentralized community.
As far as the current scenario is concerned, smart contract heavily relies on Oracles which provide an effective interface between the contracts and the external source to push the required data.
Considering the fact that Smart Contracts are immutable in nature if the oracles push inaccurate data to the contract, the contract will undoubtedly result in a faulty execution and end up favoring some malicious actor, and there will literally be nothing to undo this procedure.
Moreover, with so much money locked up in these smart contracts, it must be kept in mind that there always exist some malicious actors who continually try to manipulate or corrupt this data. And with some of the biggest Defi hacks this year like the bZx hack, Harvest, Cheese Bank hack, etc, the manipulation of decentralized price oracles can no more be overlooked.
The Story behind Price Oracle Manipulation Attacks
This year we a remarkable rise in the Price Oracle Manipulation attacks.
In order to ensure utmost security in the defi protocols that we are about to build in the future, it's extremely crucial for us to understand the entire procedure of how these attackers are capable of wiping out millions of dollars by simply manipulating the oracles.
Since we are specifically focusing on the Decentralized version of oracles, it must be kept in mind that such oracles calculate prices using the data that is completely on-chain.
In order to effectively understand how the price oracle manipulation actually works, let’s consider an example of a simple decentralized lending protocol. This lending platform allows the users to deposit a particular asset/token as collateral and borrow any other asset up to a certain ratio (Collateralization ratio).
Now, suppose Sam wants to borrow some BAT tokens by locking up his ETH.
In simpler terms, considering the current price of ETH to be 400 BAT tokens (1 ETH = 400 BAT ). Hence whenever SAM deposits 375 ETH, he gets 100,000 BAT tokens in return, keeping in mind the collateralization ratio.
But WAIT.
How exactly does the lending protocol ensure that the current price of 1 ETH is equal to 400 BAT 😕 ?
Well, the lending protocol queries a decentralized oracle to get the current price of ETH.
Let’s say the lending protocol reaches out to Uniswap and looks for the ETH/BAT pair.
The current ETH/BAT pair from Uniswap shows that there are 8000 ETH as well as 3200,000 BAT. In other words, it shows that 1 ETH is equal to 400 BAT tokens.
The Manipulation Begins
As soon as SAM realizes how heavily the lending protocol relies on the on-chain oracle price data, he figures out that the contract is vulnerable to price oracle manipulation and decides to exploit it 😈.
The ultimate goal of Sam is to boost up the price of ETH so that he could get more BAT tokens from the lending protocol for the same amount of ETH as before.
Now in order to increase the ETH price in the ETH/BAT pair of Uniswap, he must decrease the quantity of ETH in the pair by increasing the quantity of BAT. The most effective way to do so is to buy most of the ETH from the ETH/BAT pair.
Therefore, SAM swaps 5000 ETH from the ETH/BAT pair. Thus reducing the quantity of ETH in the pair and increasing the quantity of BAT tokens.
Confused 😳?
Alright, let’s understand each of these steps in detail.
Let’s observe this entire manipulation in 3 crucial steps to figure out how exactly this price change affects the lending protocol.
a. Initial Scenario:
- ETH/BAT pair in Uniswap has 8000 ETH and 3200,000 BAT.
- Therefore, 1 ETH = 400 BAT tokens.
b. During Price Manipulation:
- First of all, Sam swaps 5000 ETH for 2,000,000 BAT on Uniswap.
Notice how Sam took the majority of the ETH from ETH/BAT pair(more than 50%).
- ETH/BAT pair now has 3000 ETH and 5200,000 BAT.
- Hence, the current price of ETH becomes 1 ETH = 1,733.33 BAT tokens.
- Thus, Sam has been able to boost up the price of ETH from just 400 BAT(1 ETH = 400 BAT) to 1,733 BAT tokens(1 ETH = 1733 BAT).
- Now he moves to the lending protocol and deposits the same amount of ETH, i.e., 375 ETH to get BAT tokens.
- However, since the price of ETH is now much higher, instead of getting 100,000 BAT tokens, Sam gets 433,333.33 BAT tokens for the same amount of ETH, i.e., 375 ETH.
c. Final Stage
- Once Sam grabbed all the high profits, 💰he can simply swap the ETH back into the pair.
- Or, if he took a flash loan to initiate this entire price oracle manipulation hack, he can simply repay the loan and still walk away with higher profits.
QUICK QUESTION
In the Price Manipulation example, the attacker SAM simply buys 5000 ETH from Uniswap.
But, how did SAM have access to such an enormous amount of ETH?
Well, one possible argument in support of this could be, SAM IS RICH ENOUGH.
However, the probability of this is quite low since 5000 ETH is an incredibly large amount. Therefore, is there any other way for SAM to have instant access to 5K ETH to carry out this hack?
You guessed it right, Flash Loans.
Flash Loan Attacks
To begin with, let’s first understand what exactly are Flash Loans.
When speaking about Loans, the very obvious kinds are Secured Loans & Unsecured Loans.
Secured loans require collateral from the borrowers. Moreover secured loans always wish to ensure minimum risk due to which heavy loans are often not accepted.
Whereas, on the other hand, an unsecured loan doesn't’ really demand any collateral and also accepts heavy loans but at the same time is extremely risky for lenders.
So, under which category do Flash Loans belong? 😕
Well, in simpler terms, Flash loans are kind of Unsecured Loans. You can literally borrow any amount without providing any collateral or passing any credit check.
Yep, it’s that simple. 😃
However, there’s a catch.
The way Flash Loans ensure security might not be very intuitive at the very first glance.
Flash loans ensure that the entire procedure of borrowing and repaying of the loan must be done in the SAME TRANSACTION.
So you can borrow as much amount you wish through a flash loan, use it, but must pay back the borrowed amount within the SAME transaction.
What if you don’t PAY back the LOAN?
Truth be told, that’s not really an option. 😄
This is because Flash loans must be paid back in the same transaction or else the entire will be reverted back.
In other words, if the loan is not paid back within the same transaction, it’s as if the loan was given to the user. Everything goes back to as it was.
Not really Intuitive, Right?
Well, this is one of the many interesting functionalities that is executable and achievable with Smart Contracts in the world of Blockchain. To be precise, EIP 140 does this magic.
Now the quite obvious question that might pop in your bain is:
If Flash loans ensure such effective layers of security, how can there be Flash Loan Attacks?
Diving deep into Flash Loan Attacks
The best way to understand how a Flash Loan attack is executed is by observing a real-world flash loan attack.
Quite interestingly there were 2 remarkable flash loan attacks this year with an almost similar pattern.
Before we evaluate the flash loan attack, it's imperative to note that 📝
There is nothing wrong with FLASH LOANS in particular. They aren’t vulnerable themselves but are one of the many reason behind some massive attacks.
Just in case you didn’t really get the gist of the sentence above, be patient and stay with me on this. There will definitely be a sudden click in your brain as I explain the procedure of flash loan attacks and you will understand it all.
I promise 😐.
All right let’s begin now.
Understanding the bZx Attack:
The margin trading protocol bZx witnessed 2 massive flash loan attacks this year. Since both of these attacks followed an almost alike pattern, let’s understand the first one to get the gist of how it was executed.
- First of all, the attacker took a huge Ether flash loan of 10,000 ETH from dYdX.
- Once the attacker had access to this enormous amount of ETH, this entire ETH amount was then divided and sent to 2 other lending platforms, i.e., Fulcrum & Compound.
- The attacker used 5500 ETH as collateral to take a loan of 112 WBTC from Compound.
- A small portion of this loan amount, i.e., 1300 was sent to Bzx’s Fulcrum trading platform. This was specifically done to short ETH against WBTC.
- The attacker was now ready to initiate his next move to cause a massive slippage within the market. Hence, 5637 ETH was borrowed using Kyber’s Uniswap for almost 51 WBTC.
Note: Slippage can simply be understood as the difference between the Expected price and the price at which the trade is actually performed.
Remember that the attacker took some WBTC from Compound initially(Step 3)? Well, it was finally the time to make some profit using those WBTC.
6. Therefore, the attacker simply swapped the 112 WBTC on Uniswap. Although the loan of 112 WBTC was taken for 5500 ETH(Step 3), after the massive slippage, the attacker was able to swap it for 6871 ETH on Uniswap.
Through this entire hack, the attacker grabbed a heavy amount of 1193 ETH. In other words, the attacker was able to make an incredibly high profit of $318,000 approximately.
7. Finally, the flash loan of 10,000 ETH from dYdX was paid back.
Woah. I guess that was a lot to consume. 😫. Do not stress out if you didn’t get the whole deal at the very first glance.
The most imperative part to note here is the fact that there is nothing wrong with the working mechanisms of flash loans. They execute as expected.
The problem lies in the fact that flash loans make anyone capable of accessing an enormous amount of funds without any collateral. And these funds can then quite easily be used to manipulate the entire market, cause massive slippage, etc.
External Calls
The vicious side of external calls in Smart Contracts got enormous attention after one of the most renowned hacks in the history of the crypto world, i.e., The Dao Hack on June 17, 2016. The hack where the attacker was able to steal 3.6 million ETH in the very first few hours of the attack by sampling the reentering the contract again and again.
This sort of attack is what we now call the Re-entrancy Attack.
One can never deny the fact that the first thing that pops-up in our brain while talking about external calls is the re-entrancy attack. However, there is a crucial detail that must be kept in mind while dealing with external calls.
While making an external call you actually shift the control over execution to an external party. Now, one of the most crucial parts that must be noted here is the fact that re-entering the contract is just one of the many things that the attacker can do with an external.
In simpler terms, considering the current scenario of contracts and their composability, external calls do not just lead to re-entrancy but could potentially result in a wide range of attacks if not handled properly.
Although the issues with the external calls are quite concerning, we cannot simply stop using external calls since they have their own significance.
Therefore, the most tactful approach is to follow a procedure that minimizes the damaging impact of external calls effectively.
How exactly can we minimize the repercussions of an EXTERNAL CALL in Smart Contracts?
While this is an extremely challenging question to answer, some of the most renowned names in the Security Audit world like Samczun, Scott Bigelow have tried their best to provide some really effective techniques that one can implement.
In simpler terms, we can effectively minimize the repercussions of external calls in our contracts only when we understand how to accurately spot the blunders we do while making external calls in the first place.
- Identifying External Calls
The very first step is to identify the external calls present in the contract. Figuring out the loopholes in an extremely large contract can undoubtedly be quite troublesome.
Therefore, in order to simplify the complexities involved, it’s always a better idea to locate all the external calls present in the contracts.
2. Can the CALL be manipulated?
Once we have identified the external calls, it’s now time to figure out if these external calls provide a path for the malicious actors to gain control over execution.
There is no denial in the fact that while using low-level calls, there is always a potential exploit scenario where the attackers could use the fallback function to all the bad things they want. Classic Re-entrancy scenario…Isn’t it 😎?
While such instances of external calls are caught at the very first glance, there exist enormous other instances of such calls that go unnoticed.
For instance, in the case of reading a simple public field, one might assume there is no way for such a call to be hooked.
However, there lies an interesting fact that is often overlooked while using older versions of Solidity.
Quite interestingly, certain versions of solidity that are older than 0.5.0 use a simple CALL opcode even when you call a View Function. In simple terms, in older versions of solidity, even reading a public field could lead to unsafe external calls that can be easily manipulated.
However, with newer versions of solidity, this issue is effectively handled. It is because the newer versions of Solidity(versions after 0.5.0), uses the STATIC CALL opcode while reading such fields. It means the EVM strictly ensures that no state modifications take place in any view functions.
Hence, Always use the STABLE and UPDATED versions of Solidity 📝
3. Check if any of these BAD Patterns exist while using external call
a. State changes before the external calls
The very first part that must be noted is if there are state changes that occur before the external call is made. Since the state change only takes place after the function (with the external call) is called, it’s quite possible for the attacker to take advantage of it within the external call to the caller of the function.
b. Data being read after the external call (and if it’s possible to manipulate it)
Secondly, it’s imperative to check if there is any data read that happens after the external call.
For instance, let’s consider that the data is ready after external calls to execute a certain logic.
However, since there has been an external call before this data read and the control over execution was slightly shifted to another party, it’s quite possible for the data to be manipulated.
attacksA malicious actor can take advantage of this data being read after the external call and may be able to execute this logic in his own desired way.
c. Data being read before external call but modified once the call is executed.
This is undoubtedly one of the worst patterns you might notice since this was the one that led to the Re-entrancy attack. 😔
Let’s take the following example to understand this pattern
1. function badWithdrawFunction() external{
2. uint256 amount = balances[msg.sender];
3. require(msg.sender.call.value(amount)());
4. balances[msg.sender] = 0;}
As can quite clearly be seen in the above example:
- Line 2: the user’s balance is being read.
- Line 3: the external call is made
- Line 4: the same data is being modified.
The amount variable stores the current balance of the attacker and is sent to the user during the external call, but the balance is never updated before the external call.
Now, once the attacker arrives at Line 4, the external call gives him control over execution. And with just a simple fallback function, the attacker can call the same badWithdrawFunction once again.
Since the attacker is calling the function again and again, the execution never reaches Line 4 and the balance of the attacker is never updated to ZERO. Thus, the attacker can easily drain all the funds to his contract due to one bad pattern of code.
Significance of Smart Contract Audits
The rise of Decentralized Finance is inevitable. The DeFi market is growing at an incredibly exponential rate.
However, this year has quite clearly proved that, with so much at stake, it’s extremely necessary to consider the best security practices while developing the Smart Contract or building an entire Decentralized Application.
Most importantly, it’s high time for us to understand that smart contract audits can no more be neglected.
With a significant dependency on smart contracts, DeFi audits become crucial where a third party reviews every line of code and helps to identify the bugs and bottlenecks.
If left unaudited, the DeFi contracts may result in setbacks that include loss of funds and manipulation of the system. Sometimes, it may also lead to the shutdown of the company.
Therefore, it becomes necessary to check the quality of the team auditing your DeFi contract and get acquainted with their process of auditing.