We first go over some details about the attack that’s not related to the main vulnerability.
Then, we will look at the main vulnerability.
To find the attack vector, let’s go through the exploit locally and see what actually happens.
The tools we used here are
The exploiter’s address is 0x14c19962E4A899F29B3dD9FF52eBFb5e4cb9A067.
The first transaction related to the address is this one.
Here, we see the account is funded by 0x8D0347eCb9344a6ce5BbaFA45eEceE68e53A008D.
Looking at that address’s internal transactions, we see the exploiter is funded via Tornado Cash.
Next, the attacker creates a contract 0x6cFa86a352339E766FF1cA119c8C40824f41F22D.
The attacker then calls the function App() onto this contract. We run this in Foundry and see this
OK, a bunch of approvals. Looking up the relevant addresses, we see that it’s just approving all the tokens to relevant DFX Finance pools. We can now make an educated guess that the attacker will go through all these pools and exploit them. Therefore, we can simply look at one or two exploit transactions to see what happened.
The next transaction is the big one, and we can suspect that this is the exploit tx. We see that the transaction targets the DFX-XIDR-USDC pool. To check, let’s see the token balances after the transaction was processed. Since we can see from etherscan that the relevant tokens are USDC and XIDR, let’s look at them.
Running this on block number 15941673 and 15941674, we see that the balances increased.
This is already at least $200K in profits, so this is an exploit transaction indeed.
Meanwhile, if we look at this exploit transaction, we see that UniswapV3 flash loans are used
We see that USDC and XIDR are flash loaned from Uniswap V3, so initial capital is required.
So before we go deeper inside how the attack actually works, we can consider the attacker’s strategy regards the need for initial capital. From the fact that the attacker flashloaned both USDC and XIDR from Uniswap V3 to attack the DFX’s USDC-XIDR pool, we can guess that the attacker requires both tokens to pull off the attack. Since the attacker now gained some capital via flashloan-assisted attack, the attacker does not need to use them anymore. Indeed, if the attacker needs some other token (for example, EUROC) the attacker simply swap some USDC. We can see that this is the case by noting that
For example, this transaction is the first exploit tx that deals with GYEN.
We see that the exploiter swaps some USDC for GYEN by looking at the call trace.
We also see some housekeeping done by the exploiter, after the very first exploit tx.
These five transactions
so the attacker now doesn’t have to worry about gas costs anymore.
We also see that the attacker took out the stolen money, then either
This fund retrieval part starts at block 15941949. Now let’s actually take a look at the attack.
As we mentioned before,
Therefore, we take a look at the exploit transaction that doesn’t use Uniswap V3 flashloans or starts with a swap. That transaction would be the second tx for USDC-XIDR.
Looking at the call trace again and see the calls for the pool contract, we see that
We can already get an idea on how this attack happened. One scenario is that the flashloan mechanism simply looks at its ERC20 balances to check if the contract that took the flashloan has returned its assets. In this case, the attacker can deposit the flashloaned assets to the pool. The pool contract will think that we have returned the assets as the ERC20 balances are back to normal, but in reality we deposited the assets, so we can withdraw them later as we want.
To check if this is the case, let’s take a look at the pool contract.
Indeed, we see that this is the case. There is no reentrancy protection for flash(), and the flashloan check is done simply using the ERC20 balances. We also see why the attacker required some initial capital - it’s because the attacker had to “pay” (deposit) the flash loan fee as well.
We note that this attack vector was in the pool contracts, which was not in the audit scope of our security audit of DFX Finance which was done on May 2022.
Our audit was for DFX Finance’s algorithmic stablecoin, which can be checked in this repository.
First, appropriately preventing reentrancy is always a good practice.
UniswapV2 pairs support flashloans, but the function is reentrancy protected.
If you want professional help at preventing such attacks, ask us for an audit.
About KALOS
KALOS is a flagship service of HAECHI LABS, the leader of the global blockchain industry. We bring together the best Web2 and Web3 experts. Security Researchers with expertise in cryptography, leaders of the global best hacker team, and blockchain/smart contract experts are responsible for securing your Web3 service.
We have secured over $60b worth of crypto assets across 400+ global crypto projects — L1/L2 projects, defi protocols, P2E games, and bridges — notably 1inch, SushiSwap, Badger DAO, SuperRare, Klaytn and Chainsafe.
KALOS is the only blockchain technology company selected for the Samsung Electronics Startup Incubation Program in recognition of our expertise. We have also received technology grants from the Ethereum Foundation and Ethereum Community Fund.
Secure your smart contracts with KALOS.