
Decentralized finance (DeFi), as a popular project form in the blockchain ecology, its security is particularly important. Since last year, dozens of security incidents have occurred.
As a long-term research team (https://blocksecteam.com) concerned with DeFi security, BlockSec has independently discovered a number of DeFi security incidents, and the research results have been published in top security conferences (including USENIX Security, CCS and Blackhat). In the next period of time, we will systematically analyze DeFi security incidents and analyze the root causes behind the security incidents
Past review:
(2) [BlockSec DeFi Attack Analysis Series 2] Give away everything: Sushiswap fees stolen
0x0. Preamble
In the early hours of March 9, 2021, Beijing time, several V2 crowdfunding pools of DODO, a decentralized trading platform on Ethereum, were attacked. The token in the pool staged a trick of changing the civet cat for the prince. However, from the subsequent analysis, the development of the matter obviously deviated from the attacker's expected track...
If you are an Ethereum novice and you happen to like to read stories, you can start reading from 0x1 below. If you like simple and direct attack analysis, you can scroll down to 0x2 and start reading.
first level title
0x1. Event review
"Did the attack succeed? It succeeded, but not completely." This may be the psychological portrayal of Xiao A at that time
No code, no bug
secondary title
0x1.1 Concept Analysis
The DODO V2 crowdfunding pool has been mentioned so many times, so what is it? To put it simply, it is a pool of funds, but the funds in this article do not refer to the legal currency we are exposed to every day, but the tokens (ERC20 tokens) on Ethereum. When this kind of fund pool is initialized, two kinds of valuable ERC20 tokens on the chain will be set as the token pair of this pool (remember this point, we will test it later), and then users can use the services provided by these pools normally. In this attack against the DODO V2 crowdfunding pool, Little A used the flashloan service provided by the pool.
Compared with ordinary loans, flashloan has the characteristics of borrowing a large amount of funds without collateral, and rolling back the status before the money is paid. To put it simply, it can be empty-handed. If the last loaned money is lost after one operation, it doesn’t matter if you still can’t make it up. All related status will be rolled back to before the loan, and the only loss for the borrower is other than the formalities. In addition to fees, there may only be time. The logic of using flash loans is also very simple, that is, users borrow money from the fund pool --> operate on the borrowed money --> repay the money, and these need to be completed in one transaction.
Ok, after a brief understanding of related concepts, let's look at the operation of Little A.
0x1.2 Xiao A's coquettish operation
Little A did two things next.
The first thing is to create two ERC20 token contracts. To put it bluntly, two counterfeit coins (because they are worthless) are called FDO and FUSDT. After creating these two counterfeit coins, A will deposit them in the In the DODO pool that will be attacked.
The second thing Little A did was to use the flashloan service of the DODO V2 crowdfunding pool. As mentioned above, one part of the logic of using flash loans is to operate on the borrowed money, and the protagonist of this article, Xiao A, has played tricks on this link.
Little A found that this DODO V2 crowdfunding pool can be re-initialized artificially, and there is no limit. Then Little A re-initialized the pool after lending the money, and the token pair set at the initialization became the two counterfeit coins FDO/FUSDT created by Little A himself (this is the test point mentioned before, now it’s passed the test. ). And Little A has pre-deposited a sufficient amount of two kinds of counterfeit currency into this pool through the first thing he did above before borrowing money, which caused the pool to check the situation of Little A’s debts, so The checked token is no longer the previous real currency, but the counterfeit currency deposited by A, and the amount is sufficient. In this way, Little A used the counterfeit money to set out the real money.
We can make a simple analogy to the above process, and the details are not shown. There is a bank, and this bank can be compared to the fund pool mentioned above. At the same time, the bank also has a small book to keep accounts, but there is a record on the home page of the small book [the bank only handles RMB, and the reserve is 100]. As for other currencies, either the US dollar or the Vietnamese dong. Users can also deposit in it, but the bank doesn't care about you. Although it will keep accounts in its small books, it only looks at the records involving RMB when checking.
In order to analogize the problem that the crowdfunding pool can be reinitialized, it can be understood in this way. There is a problem with this small book. The problem is that the rule on the homepage [the bank only handles RMB] is written in pencil, and this small book is placed in the window, and outsiders can change it with an eraser and pencil. Then this problem was discovered by Little A. He first deposited 100 VND in this bank, and the bank would record [Little A deposits 100 VND in the bank]. Then little A goes to the bank to lend 100 RMB, and the bank records [Little A borrows 100 RMB from the bank]. Note that the bank will check the borrowing and deposit of RMB by all users and compare it with the reserve amount to confirm whether any user has borrowed RMB but has not repaid it.
As soon as he finished borrowing the money, little A took out the pencil and eraser he had prepared and changed the regulations on the homepage of the small book to [Our bank only handles Vietnamese Dong, with a reserve of 100]. Then when the bank checked the amount, because the regulation was changed to only deal with Vietnamese Dong, it was found that the reserve amount of Vietnamese Dong was the same as the amount of Vietnamese Dong deposited by Little A, which meant that no one owed the bank money. Then Xiao A took the loaned RMB and left without looking back.
Little A’s idea of attacking the DODO V2 crowdfunding pool is as mentioned above, and the next thing Little A has to do is to put his ideas into practical actions. The attack that this article analyzes from the contract code level is the attack mentioned above, but our story is not over yet. Those who don’t want to continue reading the story can directly scroll down to the attack analysis section of 0x2, and for the rest of the judges, please allow me to continue telling you the story.
0x1.3 Attack process: Eighteen bends of the mountain road
The first time. The praying mantis catches the cicada and the oriole follows
Let's continue the book.
The project party, that is, DODO, has created multiple pools with the same logic, and these pools have the same loopholes. The pool that Little A targeted for the first time was the (WSZO/USDT) pool. WSZO and USDT are two valuable tokens (ERC20 token). After happily writing his attack logic into a transaction, he was about to lie down and collect money, but at this moment, something went wrong.
We know that there is a transaction fee for transactions on Ethereum, which is paid by users to miners. Therefore, in order to maximize their own interests, miners will check the transaction fees of each transaction and arrange them in order when they package transactions from the pengding pool and prepare to go on the chain. Those with high transaction fees will be put on the chain first. And because of the decentralized mechanism of Ethereum, the law of the dark forest also applies here. Attackers, arbitrageurs, or early runners of DeFi (decentralized finance) projects are lurking all over the world. Once they find their targets, they will swarm them. As for who can succeed in the end, it depends on who pays the transaction fees in addition to technology and other factors. Taller.
Back to the protagonist, little A, he found a loophole and was going to take the opportunity to make a wave of money, but little A's actions were discovered by another character—the rushing robot. Let's call this rushing robot Little B. Little B made a fuss about the transaction fee. He increased the gas price of the transaction, thereby increasing the transaction fee of this transaction. This makes the miners package the transaction of small B first when packaging the transaction. Generally, this kind of operation by Little B is called front running. When it was the turn to package the small A transaction, the WSZO and USDT in the WSZO/USDT pool were empty, leaving only a bunch of worthless (FDO/FUSDT).
Little A may have thought that the failure this time was just an ordinary front-running transaction, so he repeated the old trick. It’s just that this time the target has been changed to the (ETHA/USDT) pool, and in order to prevent being robbed, Little A increased the gas price of the transaction in this transaction. But what little A doesn't know is that he has been targeted by little B.
With the same routine and the same method, Little A was snatched away by Little B again.
The second time. Cheng Yaojin was killed halfway
So far, Little A made a wedding dress for Little B in the two attacks, and even lost the transaction fee himself! Little A was so angry, so he learned from the pain and set his sights on the next pool (wCRES/USDT). And this time little A successfully bypassed little B's monitoring. Things have developed to the point where it seems that Little A is about to succeed, but the reality is that he likes to joke with Little A.
Although the third attack bypassed Little B, Little A did not directly transfer the money to his own address after successfully withdrawing the money, but created a new contract to receive the money. Little A's idea is to temporarily store the money in this new contract first, and then transfer it to his account. However, there is another loophole in Little A's contract for temporarily storing stolen money, that is, anyone can withdraw (withdraw) the funds in the contract from this contract.
However, this contract had a loophole that allowed anyone to withdraw assets from it.
It just so happened that this vulnerability was discovered by another character (Little C). Therefore, when Little A issued a transaction to get back the stolen money from this contract, both of them were robbed again, but this time the preemptor became Little C.
Seeing this, Little A is both an attacker and a victim of a front-running transaction. This wave, little A can be regarded as stealing chickens but losing money.
The third time. Stubborn little A
As mentioned earlier, there are multiple pools with the same logical loophole. Little A is ready to launch his fourth attack again. This time, the target is changed to the (DODO/USDT) pool. This time, little A learned to be smart. On the one hand, he replaced the contract that temporarily stored the stolen money with a new contract. On the other hand, little A also combined the process of token transfer into one transaction to avoid the third The case of being snatched away by Little C in the second attack. But this time, Little A, who did not hit the south wall and did not look back, finally succeeded in getting real money (DODO/USDT) with counterfeit currency (FDO/FUSDT).
Chapter 4. Go crazy and bite yourself
Is Little A satisfied after the four attacks are finally successful? The facts tell us the answer is no.
I don't know what little A thinks, it may be that he finally succeeded after going through twists and turns, which caused him to be too excited. In this fifth attack, his target was the (wCRES/USDT) pool. Does it look familiar? That's right! This pool is exactly the target pool of Little A in the third attack. After the third attack, the pool has changed from the (wCRES/USDT) pool to the (FDO/FUSDT) pool, that is, the real coin pool has become a counterfeit coin pool. Therefore, in this round of attacks, the result obtained by Little A using the same attack routine is nothing more than exchanging new counterfeit coins for old counterfeit coins...
And these two counterfeit coins were made by Xiao A himself. Maybe, Xiao A is still a nostalgic person...
Our story about little A is also coming to an end. Perhaps Ethereum is a dark forest for attackers, and the identities of hunter and prey are not static in this special arena. Always remember that when you gaze into the abyss, the abyss gazes into you.
ok, the next step is the serious attack analysis link.
first level title
0x2. Attack Analysis
For ease of understanding, the following will take the third attack as an example to analyze, and the pool involved is (wCRES/USDT) pool
0x2.1 code analysis
The functions mentioned below all come from the contract code of the fund pool (wCRES/USDT) and are involved in this attack.
0x2.1.1 getVaultReserve function
First look at the getVaultReserve function. The function of this function is very simple, that is, when the user calls it, it will return the reserve of the token pair in the current pool.
0x2.1.2 flashloan function
The picture above is the flashloan function of the fund pool contract in this attack. It can be seen that when the user calls this function, the corresponding number of tokens will be transferred to the address represented by the parameter assetTo according to the two parameters of baseAmount and quoteAmount passed in by the user. At this point, the loan link of flashloan is completed. Looking down the code, as long as the data is not empty, the external logic will be triggered. And this external logic is implemented by the caller himself, and the realization of this attack is precisely when this external logic is executed.
0x2.1.3 init function
The above figure is the most critical initialization function init in this attack. It can be noticed that this function is called externally, and the most important thing is that this function has the following two characteristics:
[No permission requirement] This means that anyone can call this function from the outside.
[Can be called repeatedly] means that the init function can be called at any time to reinitialize the pool except for being called once when the pool is built.
When the caller calls this function, the two parameters baseTokenAddress and quoteTokenAddress passed in will be used to reassign the variables _BASE_TOKEN_ and _QUOTE_TOKEN_ respectively. And the change of these two variables means that the token pair of this pool will also change. And this is the reason why the wCRES/USDT pool becomes FDO/FUSDT.
0x2.2 attack process
The flow of the attack transaction is shown in the figure below
Deal flow analysis can use our team's deal analysis tools:https://tx.blocksecteam.com/
Step 0
The attacker first created two ERC20 token contracts (FDO and FUSDT), which can be simply understood as creating two counterfeit tokens (worthless). And transferred a large number of these two tokens to its own address (0x368a6), paving the way for subsequent attacks.
Step 1
The attacker calls the getVaultReserve function of the fund pool contract to obtain the current reserves of wCRES and USDT in the pool to prepare for the next attack.
Step 2
According to the reserves obtained in Step 1, the attacker calls the transferFrom function of the two counterfeit currency contracts to transfer counterfeit currencies (FDO and FUSDT) slightly more than the reserves to the fund pool contract (DLP), so as to ensure that the balance check of the flashloan function can pass.
Step 3
The attacker then calls the flashloan function of the fund pool contract (DLP) to lend out real coins (wCRES and USDT) slightly less than the fund pool reserves.
Step 4
After the flashloan function transfers wCRES and USDT to the contract address preset by the attacker, it will automatically call the attacker's external logic. The attacker called the initialization function init of the wCRES/USDT pool in the implementation of the external logic, and replaced the token pair of the pool with FDO/FUSDT.
Step 5
As shown in the figure below, after the flashloan function executes the external logic, it will check the token (token) balance of the current pool. But it should be noted that since the token pair of the pool is replaced by FDO/FUSDT, the balance represented by baseBalance and quoteBalance is also the balance of FDO and FUSDT.
At the same time, since the attacker isStep 2 first level title
0x3. Summary and security recommendations
The main reason for this attack is the init function of the DODO V2 crowdfunding pool. Looking at the calling of this function, it can be found that the normal logic should be that this function can only be called once when the pool is first built, and then the access permission should be set, and it cannot be called repeatedly. The attacker took advantage of the vulnerability that the init function can be called repeatedly to reinitialize the pool, combined with flashloan to withdraw the real money in the pool with counterfeit money, thus completing the attack.
Therefore, our suggestions to relevant project parties are as follows:
Do a good job of authority review on the key functions of the project contract, so as to avoid the loss caused by the misuse of core functions due to low authority requirements.
first level title
0x4. Reference
secondary title
The external addresses and contract addresses involved in the article
Transactions covered in this article
first attack
second attack
third attack
C's frontrunning transaction (preempting A's transfer of the token USDT)
C's frontrunning transaction (preempting A's transfer of token wCRES)
fourth attack
fifth attack