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 of the massive attacks on some of the most renowned protocols like bZx, Cheese Bank, Harvest Finance, Value Defi, etc.
Source: https://ciphertrace.com/cryptocurrency-intelligence/
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’s 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.
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.
Source: Decenter
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 the 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.
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.
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%).
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.
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.
To begin with, let’s first understand what exactly are Flash Loans.
While 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.
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.
Source: Finematics
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.
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.
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.
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.
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
function badWithdrawFunction() external {
uint256 amount = balances[msg.sender];
require(msg.sender.call.value(amount)());
balances[msg.sender] = 0;
}
As it can quite clearly be seen in the above example:
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.
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.
Also published here.