XCarnival NFT lending protocol vulnerability analysis
According to SlowMist, on June 27, 2022, hackers exploited a critical flaw in the XCarnival project and made off with 3,087 ETH (about $3.8 million). XCarnival is a decentralized NFT lending platform that was built on the Ethereum network. The team working on the project has been made aware of the security breach and is working to patch it. They also guaranteed that those affected will be provided with a workaround. Following an immediate investigation, SlowMist’s security team made the following determinations:
Core contract addresses:
XNFT address: 0x39360AC1239a0b98Cb8076d4135d0F72B7fd9909
Attacker EOA address: 0xb7cbb4d43f1e08327a90b32a8417688c9d0b800a
Attack contract addresses:
Analyzing Critical Vulnerabilities
1.The attacker uses the ‘pledgeAndBorrow’ function in the XNFT contract to use NFTs as collateral and borrow xToken.
NFT is transferred and an order is generated using the ‘pledgeInternal’ function:
2.Then, a call is made using the ‘withdrawNFT’ function in order to extract the pledged NFT. This function first checks to see if the order has been closed. If it hasn’t, it checks to see if the NFT hasn’t been withdrawn and the loan amount is 0. If none of these conditions are met, it then determines that the NFT has not been withdrawn and the order is still active (no debt). NFTs that are used for collateral can be withdrawn.
3.The above shows the preparatory operation of generating an order prior to initiating the attack. The attack itself starts when the attacker uses the order to directly call the ‘borrow’ function in the xToken contract.
Using the ‘borrowInternal’ function, the ‘borrowAllowed’ function in the controller contract is externally called in order to determine whether a loan can be borrowed.
You can see that the ‘borrowAllowed’ function calls the ‘orderAllowed’ function which considers information regarding the order, but neither of these two functions will consider the status of _order.isWithdraw. Therefore, the attacker can use the previously generated order (where the collateralized NFT has been withdrawn) to call the ‘borrow’ function of XToken to borrow repeatedly. Since the loaned NFT has already been presented, the attacker can do this without making repayments, therefore making a profit.
Transaction Analysis of Attack
Although all of the attack transactions have the same methodology, only one will be covered in detail below.
Preparing for the attack — the transaction that generated the order:
1.First, the attacker sends the NFT to the attack contract with authorization, and then, using the xNFT contract’s ‘pledgeAndBorrow’ function, the attacker leverages the NFT to make a purchase order and take out a loan. It should be noted here that this function can also control any incoming xToken. The user entered his own xToken contract address and set the loan amount to 0 in order to fulfill the requirements of not being liquidated and having no debts if the NFT is successfully offered later.
2.The attacker then calls the ‘withdrawNFT’ function to withdraw the loaned NFT:
Official attack transaction hash:
Because the NFT was withdrawn during the preparation step, the attacker is not expected to have to return this in order to acquire the funds; instead, he just invokes the borrow function of the xToken contract and sends in the orderID of the previously produced order 22 times (orderID: 45–66) to make a profit.
The essence of this vulnerability is that there is no check while borrowing to see whether the NFT in the order has been withdrawn, allowing an attacker to borrow without repayment after removing the NFT for their own benefit. The SlowMist security team has responded to these issues by suggesting a precautionary measure: before borrowing, carefully evaluate the order status to see whether the collateral has been removed.