CTF-ntf-bonanza

题目源代码:点击

要求是:新的 NFT 交易合约 BonanzaMarketplace 已经推出,它允许交易选定的白名单 ERC721 和 ERC1155 代币。您的挑战是获得所有列出的 NFT。

根据源码,可以发现此时的NTF都是ERC721代币,所以了解ERC721非同质化代币标准,会很好的理解。

要获得所列的NTF,就先看看,buyItem函数

function buyItem(
address _nftAddress,
uint256 _tokenId,
address _owner,
uint256 _quantity
)
external
nonReentrant
isListed(_nftAddress, _tokenId, _owner)
validListing(_nftAddress, _tokenId, _owner)
{
require(_msgSender() != _owner, "Cannot buy your own item");

Listing memory listedItem = listings[_nftAddress][_tokenId][_owner];
require(listedItem.quantity >= _quantity, "not enough quantity");

// Transfer NFT to buyer
if (IERC165(_nftAddress).supportsInterface(INTERFACE_ID_ERC721)) {
IERC721(_nftAddress).safeTransferFrom(_owner, _msgSender(), _tokenId);
} else {
IERC1155(_nftAddress).safeTransferFrom(_owner, _msgSender(), _tokenId, _quantity, bytes(""));
}

if (listedItem.quantity == _quantity) {
delete (listings[_nftAddress][_tokenId][_owner]);
} else {
listings[_nftAddress][_tokenId][_owner].quantity -= _quantity;
}

emit ItemSold(
_owner,
_msgSender(),
_nftAddress,
_tokenId,
_quantity,
listedItem.pricePerItem
);

_buyItem(listedItem.pricePerItem, _quantity, _owner);
}

function _buyItem(
uint256 _pricePerItem,
uint256 _quantity,
address _owner
) internal {
uint256 totalPrice = _pricePerItem * _quantity;
uint256 feeAmount = totalPrice * fee / BASIS_POINTS;
IERC20(paymentToken).safeTransferFrom(_msgSender(), feeReceipient, feeAmount);
IERC20(paymentToken).safeTransferFrom(_msgSender(), _owner, totalPrice - feeAmount);
}

从上我们可以看到,并没有对购买数量quantity的检查,所以即使购买零个NTF也是可以的,重点来了,在ERC721代币标准中,对于购买数量并没有要求,还是会发送tokenId给购买者,这就是漏洞所在

攻击思路:直接调用buyItem函数,购买零个ERC721代币标准的NTF就可以了

个人认为,这个题就是疏忽了ERC721代币的执行标准,所以对于一些主流协议,还是必须的了解。