Hello Defiers! Last weekend, decentralized finance suffered the biggest attack in its short life. This time, the attack has a happy ending, but that doesn’t take away from the fact DeFi builders need to follow better security procedures.
Emilio Frangella, engineer at lending protocol Aave, will break down the attack and very importantly, how to avoid it, in detail below. But in very rough terms, a hacker was able to drain $25 million from lending protocol Lendf.Me —almost all of the funds it held— in just under four hours, by exploiting vulnerabilities in the imBTC token and in the protocol itself. The hacker used an attack anyone in Ethereum should be painfully aware of: Reentrancy. It’s what the attackers of The DAO used to steal more than $50 million from a smart contract, which resulted in the fork between Ethereum and Ethereum Classic.
Lendf.Me had its share of controversy even before the attack, as Compound Finance, the biggest DeFi lending platform after MakerDAO, accused it of stealing its code, which is under copyright. Changes to Compound’s code added a vulnerability which resulted in Lendf.Me’s loss of funds. While users might have been put off by Compound's accusations, they also had reason to trust the platform: Just a week ago venture fund Multicoin Capital announced it led a $1.5 million investment round into dForce, the company behind Lendf.Me.
This attack comes just weeks after MakerDAO’s Black Thursday, where traders were able to take about $5 million worth of ether, and just two months after the bZx exploits, where attackers made almost $1 million. It’s becoming increasingly clear there needs to be an ecosystem-wide change in security measures to secure users’ funds. One glaring error made in this case: The potential attack to the standard used by imBTC, ERC-777, had been known since at least July. Read below for the full details, including negotiations between the hacker and Lendf.Me.
Both free and paid subscribers are getting full versions to today’s newsletter. To make sure you always get complete access to the content, archive and Discord chat, subscribe now at $10/month, $100/year, or 70 Dai on this link.
🙌 Together with Ampleforth, a digital asset protocol for a base money which doesn’t require collateral and is uncorrelated with the rest of crypto.
The Biggest Hack in DeFi Has a Happy Ending
During the weekend a hacker leveraged an exploit surface exposed by the dForce Lendf.me protocol to completely drain the platform and pull off the biggest attack in DeFi yet. Funds were returned today in an unexpected turn of events.
Quick Takes
The lending protocol Lendf.me that belongs to the dForce ecosystem was drained of $25 million worth of funds on Sunday, April 19th at around 12-2 AM UTC
The hacker leveraged a vulnerability in the LendF.me contracts using imBTC as a trojan horse
A similar vulnerability was used one day before to drain the imBTC/ETH liquidity pool on Uniswap
The hacker and dForce have negotiated using Ethereum transactions
The hacker has returned the assets stolen today
DeFi needs stricter safety procedures in handling malicious events
Smart contracts developers need to always account for reentrancy and never trust any external contract interaction
How was the attack performed?
What we have seen is a modern version of The DAO attack, which happened in 2016. The core of the attack is called reentrancy: The possibility for a smart contract function to be executed multiple times concurrently, which might bring state inconsistencies if the function is not implemented properly.
What is Reentrancy anyway?
Contracts interact. To be able to move your DAI or USDC from Compound to Aave or MakerDAO, for example, the smart contracts of each of these platforms interact with other contracts that define the currencies being used, in this case the DAI contract and the USDC contract. This complex network of interactions allows developers to implement all the beautiful things we see running on Ethereum. Everything works well when the contracts that interact trust each other. But what if we put in the middle of these interactions a malicious actor?
Imagine to have a contract that defines a Bank. You can deposit to the bank and withdraw from it at any time.
The deposit works this way:
The Bank calculates the new balance by adding the amount being deposited to the previous balance
The Bank collects the funds from the user wallet
The Bank updates the new balance of the depositor into its accounting books
The withdraw works this way:
The Bank checks the balance of the depositor and if it’s enough to satisfy the withdrawal request, it calculates the new balance
The Bank sends the funds to the depositor
The Bank updates the new balance of the depositor into its accounting books
A bank that works like this is the perfect candidate for a reentrancy attack. How would that work?
Say Alice wants to deposit 1000 DAI in the Bank, and later withdraw them. If Alice is a non malicious actor, everything works as expected.
Here you see the interaction between Alice and the Bank. Each interaction follows the sequence of actions provided earlier, and everything is consistent: Alice’s balance after the withdrawal is correctly 0 DAI.
Now let’s imagine Alice is malicious, and she has a peculiar superpower: She can obtain control of the flow of actions while the Bank is collecting the amount of DAI to deposit from her wallet (note: this is impossible with the actual DAI, but is exactly what happened in the attacks that involved Uniswap and Lendf.Me, where the attacker used a tokenized version of BTC called imBTC: more on this later). If we imagine this possible, this could happen:
First, Alice deposits 1000 DAI. Everything works as expected:
She now has 1000 DAI in the Bank. Here is where the fun begins. Alice deposits 1 more DAI, and activates her ”superpower” of regaining control of the flow while the Bank is collecting the funds to deposit:
The transfer of 1 DAI is on hold, and will be executed at the end. Alice has now the control and can do whatever she wants. So Alice executes a withdrawal, and withdraws all the funds:
So while the deposit action is still in progress and on hold, Alice is able to regain control and execute a withdrawal. Her balance is really 0, but the Bank still has to register the 1001 DAI balance from the deposit action. I think we all know where this is going:
The deposit is completed, it collects 1 DAI and sets Alice’s balance to 1001 DAI. But Alice withdrew already - so she now has 1000 DAI in the wallet, and 1001 DAI in the Bank, even though the actual 1000 DAI are not there - it’s an inconsistency of the balance sheet. The reentrancy attack has been successful. This is one of the simplest ways of performing a reentrancy attack, but there are many with different complexities. Evaluating if a code path can be subjected or not to reentrancy can become quite complex.
How do Ethereum developers protect the contracts from this attack?
There are two ways: one is using a so-called Lock, or Mutex. By putting a lock on the withdraw and deposit actions of the Bank whenever one of the others is executed, we prevent Alice from executing the withdraw, making her superpower useless:
This is the so-called Reentrancy Guard.
Another strategy is to change the way the Bank works, so that external interactions (in this case, collecting funds to deposit or transfer funds to withdraw) are always the last steps being executed. If the deposit action would work this way, instead of the original definition:
The Bank calculates the new balance by adding the amount being deposited to the previous balance
The Bank stores the new balance of the depositor into the Bank accounting books
The Bank collects the funds from the user wallet
There would be no attack surface available to Alice, and her superpower would be useless:
The immediate update of the balance by the Deposit action factually deactivates Alice’s superpower: even if she uses it, the final balance will be correct (1 DAI). This is what smart contract developers call the Checks/Effect/Interactions pattern: A way of writing code which requires that interactions with external actors always happen at the end of each action.
So how did the attack happen?
The attack flow followed what we just described. In this case, Alice’s (the attacker) superpower was given by one of the currencies supported by the Lendf.me contracts, a tokenized version of Bitcoin known as imBTC. ImBTC is a bit different than, say, DAI or USDC: it implements a standard called ERC777 that allows for new functionalities while remaining backward compatible with the more common ERC20 standard.
One of the possibilities offered by the ERC 777 is the ability for each token holder to define an implementer: an entity that allows token holders and recipients to react to token transfers. Here is Alice’s superpower: by defining a malicious implementer, she can get back in control of the flow while the Bank (in this case, the Lendf.me contracts) tries to collect the funds to deposit.
The caveat here is that the Lendf.me contracts (which are a slightly modified instance of the Compound V1 contracts) do not have any Reentrancy guard in place, and more importantly, they don’t follow the Checks/Effects/Interaction pattern, which makes them particularly vulnerable to attacks executed using the ERC 777 implementers.
Using the strategy described above, the attacker managed to alter the accounting books of the Lendf.Me contracts. At some point, he had so many imBTC registered (but not actually deposited) in the protocol that he was able to borrow against them all the liquidity available. The contracts only check the accounting book and don’t verify if what is written in there matches the actual treasury: the attacker was in this way able to completely drain the contracts, stealing $25 million dollars worth of assets.
Gimme more data
Let’s dig into Etherscan: Apparently the attack started at 12:58 AM UTC, with this initial transaction:
Taking a look at the internal execution of the transaction, we can clearly see the reentrancy being performed on the supply() function of the MoneyMarket contract:
The doTransferIn() is the function executed during the supply() operation of the Lendf.me contracts
The attacker started to leverage the vulnerability using only 0.00021594 imBTC. He iterates the attack multiple times, to increase his imBTC balance and speed up the process.
After 12 minutes, he already had stolen 7 imBTC:
After 24 minutes, he had 290 imBTC, worth around $2 million dollars: he had depleted the imBTC reserve already, and he had inflated his balance to a point where he was able to borrow all the available assets.
After this transaction, the attacker proceeds to drain almost all the available assets in the protocol:
Almost the whole stablecoin liquidity is depleted (a few hundred thousands were still available to borrow) but the big loot is not taken yet: 55K WETH, worth around $9 million. To be able to borrow it, the attacker keeps abusing the vulnerability. The last deposit of 250 imBTC is at 2:03 AM UTC, 1 hour 5 minutes after the initial attack.
He’s finally able to borrow all the available ETH:
The contract is now completely depleted. A few hundred thousands in stablecoins are still available, and the attacker proceeds to borrow most of them. The last malicious transaction is at 3:30 AM UTC, 3 hours 32 minutes after the initial attack.
The effects of the exploit are immediately visible on DeFi Pulse:
The Total Value Locked plummets to 0 in a matter of hours. The community in the meantime started noticing that something was off:
What was the dForce response to the attack?
The Lendf.me MoneyMarket contract was paused at 4:57:29 AM UTC, one hour after all the funds were drained.
In the meantime, a big red banner “DO NOT SUPPLY” had appeared on the Lendf.me interface.
The aftermath of the attack accounts for the following stolen assets:
imBTC: 291.3471
WETH: 55,159.02134
WBTC: 9.01152
HBTC: 320.27714
CHAI: 77,930.93433
HUSD: 432,162.90569
BUSD: 480,787.88767
TUSD: 459,794.38763
USDT: 7,180,525.08156
PAX: 587,014.60367
USDC: 698,916.40348
USDx: 510,868.16067
For a total of around $24.6 million.
What happened after the attack?
The attacker proceeded to convert most of the currencies to different assets, including ETH, MKR, LINK, LEND and KNC. The swaps were executed using 1inch.exchange and Paraswap.
Attacker swapping 100K PAX for 528 ETH on 1inch.exchange
Stablecoins were supplied to Compound (USDC, DAI, WBTC) and Aave (USDT, TUSD, BUSD). The attacker borrowed around 1500 ETH on Aave using TUSD as collateral (USDT and BUSD are not enabled as collateral on Aave) but the loan was repaid shortly after. The attacker has currently around 13.5M assets in his wallet, mostly in ETH.
The hacker negotiates?
Interesting to note, 12 hours after the attack (2:12PM of April 19th) the attacker sends the following transaction to the Lendf.me admin wallet, which has the ownership of the dForce protocol:
The encoded data shows the message “0xBetter future”. After that, the attacker sends 126K USD worth of PAX to the Lendf.me admin wallet:
Clearly a sign of peace (PAX means peace in Latin). The dForce answers with an email, “0xcontacts@dforce.network”
The attacker has probably contacted dForce at this point. A few hours later this message:
It shows that there was likely contact between the parties involved. After this message, the attacker returned the HBTC and HUSD stolen, worth ~$2.8 million:
The last message sent by the dForce team doesn’t have the same friendly tone as before however: “Contact us. For your better future.”
The same communication channel has been used by many dForce users who are paying the price for the stolen funds. This is one particularly dramatic example:
The aftermath
After returning the HUSD and HBTC, no further actions have been executed by the hacker. Situation seems to be on hold: is likely going to evolve in the next few days, in one way or the other.
The end
After returning the HUSD and HBTC, no further actions were performed by the hacker until today, when all the funds were swiftly returned:
We can only guess what happened, there are multiple hypotheses - from the hacker leaking important data about his identity, to the hack being a “gray hack” in the first place (where the hacker breaks some ethical standards but doesn’t have malicious intent). I guess we will never know.
What do we learn from this
There are multiple lessons to be learned from the events that happened during the last weekend. The first lesson for developers is to never, ever underestimate how risky interacting with external, untrusted contract can be. In the Compound V1 contracts developers clearly considered the transferFrom() of the ERC20 standard as sufficiently trustable. Which is true for the vast majority of legit assets in the Ethereum ecosystem, but is unfortunately not true for certain classes of assets that might implement other standards, like imBTC.
Probably part of the problem is related to dForce using the Compound V1 contracts and listing imBTC before doing a comprehensive security assessment. The potential attack surface provided by ERC 777 tokens was disclosed to the public at least since July 2019, when OpenZeppelin provided this proof of concept of the Uniswap attack, which ironically was executed one day before the Lendf.me hack.
Also, Lendf.Me were also paused well after the attack was terminated: my personal opinion is there was margin for better reaction times, but hindsight is always 20/20. What is certain is that the Q1 of 2020 has been a devastating quarter for DeFi: Between the bZx attack, the MakerDAO 0 bid auctions that caused a leakage of collateral worth 8M, the Uniswap attack and this one, there is clear proof that DeFi requires better security standards and procedures. We know that DeFi is still very experimental and there is a wide margin of improvement, but the users need to be conscious that providing liquidity to DeFi is not a 0 risk game. Thankfully, at least this time we have a happy ending.
The Defiant is a daily newsletter focusing on decentralized finance, a new financial system that’s being built on top of open blockchains. The space is evolving at breakneck speed and revolutionizing tech and money. Sign up to learn more and keep up on the latest, most interesting developments. Subscribers get full access at $10/month or $100/year, while free signups get only part of the content.
Click here to pay with DAI.There’s a limited amount of OG Memberships at 70 Dai per annual subscription ($100/yr normal price).
About the author: I’m Camila Russo, a financial journalist writing a book on Ethereum with Harper Collins. (Pre-order The Infinite Machine here). I was previously at Bloomberg News in New York, Madrid and Buenos Aires covering markets. I’ve extensively covered crypto and finance, and now I’m diving into DeFi, the intersection of the two.
Amazing story, worthy of a Hollywood Movie. And very well explained. Congrats Camila!