OMNI Attack Analysis
0x01 Background preview
Omni is a platform for creating and trading custom digital assets and currencies. It is a software layer built on top of the most popular, most audited, most secure blockchain — Bitcoin. Omni transactions are Bitcoin transactions that enable next-generation features on the Bitcoin Blockchain. Our reference implementation, Omni Core is an enhanced Bitcoin Core that provides all the features of Bitcoin as well as advanced Omni Layer features.
0x02 Attack information
Attack wallet address:
Attack contract address
Contracts under attack.
0x03 Attack steps
- The attacker flashloan 1000 WETH from Balancer to
2. The attacker uses the flashloan function to borrow 20 Doodles and uses 13.203802230912588834 WETH to exchange 1 Doodles via sushiswap
3. Call the supplyERC721 method to stake three NFTs and lend 12.15 WETH
4.Take out two of the NFTs
5.Return the loaned 12.15 WTH and call the clearing method for the remaining one NFT
6. Continue the re-entry attack by calling the ERC721_checkOnERC721Received function during the liquidation process to stake 20 doodles and lend 81 WETH
7.take out 20 NFT, due to the return value of the clearing function will be set to the state of false, so in the take-out function for the debit and credit status error, 20 NFT can be successfully taken out
8.Since the NFT is first removed when the liquidation is performed and the money returned is deducted afterwards, the attacker makes a re-entry by removing the NFT and continues to make a judgment after the re-entry, at which point the state has changed and the 12.15 WETH previously lent does not need to be returned, so the attacker will end up with 93.15 WETH
9. Return the 20 Doodles obtained by calling flashloan and return the 1000 WETH obtained by flashloan
0x04 Vulnerability Core
The attacker does so by calling the liquidation method executeERC721LiquidationCall in LiquidationLogic.sol
When calling the _burnCollateralNTokens method, the burn function calls the _checkOnERC721Received method in ERC721
At this point, the TO address is the address of the attack contract, where the attacker implements the re-entry attack. Continue to stake 20 Doodles for borrowing.
The ID status is marked as true, and the clearing function overrides the true to false when it continues to execute the clearing function. isBorrowAny() then determines the ID status, which is false, and successfully removes the staked Doodles.
0x05 Flow of funds
The two attacking wallet addresses have transferred 800 ETH and 426.5 ETH of captured funds to Tornado.Cash
0x06 Summary and recommendations
The core of the attack is a flaw in the access control of the project’s contract, which does not restrict the re-entry of pledges in the Pool contract, allowing the attacker to maliciously call the _checkOnERC721Received function in ERC721 to carry out the re-entry attack, as well as not setting the status judgment operation before the setBorrowing() method.