Analysis of 3000 ETH stolen from NFT lending platform XCarnival

NFT lending platform @XCarnival_Lab was hacked about 7 hours ago, with at least 3000 $ETH (~$3.8 million) stolen. Below is a brief analysis of the incident:

There is a bug in the contract of the NFT lending platform: after the NFT as collateral is taken out, its orderID is still available, and you can apply for a loan here.

There are three related contracts: xETH, money here main.… 

 xNFT, NFT manager.… 

 P2Controller, a validator for many lending constraints.

Hacker… took the bad start money from Tornado. Then bought #BAYC 5110 on OpenSea.

He deployed a master control contract 0xf706…ca8d…, which generated a lot of horse-boy contracts for witches to borrow with the same NFT, such as 0x5338…3714 https: //…….

First, the master controller transfers BAYC to a certain horse (take 0x5338 as an example). Ma Zai then calls the pledgeAndBorrow() function in xNFT (mortgage and loan), the collateral is BAYC, but nothing is loaned (the loan is a fake xToken contract deployed by the master controller, the quantity is 0). This step generates an orderID (43).

These processes can be seen in this Tx, but only internal transaction. If you want to interpret it in detail, you have to dig deep into the call stack yourself.
Mazai 5338 then took out the NFT that had just been mortgaged and returned it to the general controller. The general controller will give the NFT to other horses. In such a left-handed right-handed cycle, the hacker has created dozens of orderIDs, which can then be used as loan certificates. The buggy xNFT did not revoke the voucher orderID after taking out the collateral.

Next, the master control asks all the horses to borrow money from the xETH contract in turn. The attack is complete. Hackers used air to borrow real money (the NFT collateral was taken out long ago). This is one of those tx.

The above is the approximate process. Let’s look at the details. In the xNFT contract, withdrawNFT() does not remove the orderID after withdrawal. This ID can still be retrieved when P2controller calls getOrderDetail().


In xETH, borrow() will call borrowInternal() and then call controller.borrowAllowed() to verify that the orderID is valid.


This is the borrowAllowed() function of P2controller. First, you will ask xNFT.getOrderDetail(), which is definitely done. There are various other limitations, but none of them work well, I have an analysis in the code comments. Note: The reason why the hacker wants multiple horse contracts is because there is a limit on the number of loans for a single orderID at the bottom.


Summary: The collateral is still valid after being taken out. This is a very simple and superficial contract bug. The following picture is a clear call stack of these intricate internal calls. If you want to analyze with the naked eye without tools, you can refer to the figure below if you see numbness.


Posted by:CoinYuppie,Reprinted with attribution to:
Coinyuppie is an open information publishing platform, all information provided is not related to the views and positions of coinyuppie, and does not constitute any investment and financial advice. Users are expected to carefully screen and prevent risks.

Like (0)
Donate Buy me a coffee Buy me a coffee
Previous 2022-06-27 11:42
Next 2022-06-27 11:44

Related articles