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: 278/283
Findings: 1
Award: $0.04
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: klau5
Also found by: 0rpse, 0xBinChook, 0xDetermination, 0xGreyWolf, 0xLogos, 0xWallSecurity, 0xaghas, 0xgrbr, 0xkaju, 0xlyov, AlexCzm, BARW, Blank_Space, BoRonGod, Daniel526, DanielArmstrong, Draiakoo, FloatingPragma, Giorgio, Greed, Jorgect, Matue, McToady, MidgarAudits, Nyxaris, PUSH0, PedroZurdo, Pelz, PoeAudits, Silvermist, SpicyMeatball, Tekken, Tricko, Tumelo_Crypto, VAD37, WoolCentaur, Zac, alexzoid, andywer, aslanbek, bgsmallerbear, cats, d3e4, desaperh, dimulski, dutra, erosjohn, evmboi32, favelanky, fnanni, forkforkdog, gesha17, givn, grearlake, haxatron, honey-k12, iamandreiski, immeas, juancito, kaveyjoe, ke1caM, kiqo, klau5, korok, lil_eth, lsaudit, n0kto, ni8mare, niser93, pa6kuda, peanuts, peter, shaka, sl1, soliditywala, solmaxis69, t0x1c, tallo, thank_you, tpiliposian, visualbits, vnavascues, web3pwn, yotov721
0.0352 USDC - $0.04
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L379-L380 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L462-L474 https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L83
The function reRoll()
allows a user to re-roll a fighter's attributes. The new fighter's attributes are determined using a keccak256 hash:
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L379C13-L379C100
uint256 dna = uint256(keccak256(abi.encode(msg.sender, tokenId, numRerolls[tokenId])));
And then the DNA is passed into _createFighterBase()
, where the element and weight of the fighter are determined by DNA modulo a small value:
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L470C9-L471C40
uint256 element = dna % numElements[generation[fighterType]]; uint256 weight = dna % 31 + 65;
For certain types of fighters, its physical attributes are further determined by _aiArenaHelperInstance.createPhysicalAttributes()
, which has the same core logic.
The issue is that msg.sender
is manipulatable. Since there is no restriction on the transferring of Fighter NFT (except for one account cannot own too much, and that it cannot be being staked), anyone can manipulate the value of DNA, and thereby its attributes, by transferring to an arbitrary address that they own, reroll, then transfer back.
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L539-L545
function _ableToTransfer(uint256 tokenId, address to) private view returns(bool) { // @audit there aren't restrictions on transferring return ( _isApprovedOrOwner(msg.sender, tokenId) && balanceOf(to) < MAX_FIGHTERS_ALLOWED && !fighterStaked[tokenId] ); }
reRoll()
. The NFT's attribute is now favorable to Alice.Alice was able to select her own fighter attributes, as opposed to randomizing it.
A fighter's element and weight can be modified to its owner's will using a single re-roll.
The foremost mitigation is to not use any user-supplied parameter for any randomization.
Furthermore, on-chain randomization is impossible if you rely on contract logic alone. There are dedicated ways to generate a truly random number:
Other
#0 - c4-pre-sort
2024-02-24T01:59:11Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-24T01:59:55Z
raymondfam marked the issue as duplicate of #53
#2 - c4-judge
2024-03-06T03:53:14Z
HickupHH3 marked the issue as satisfactory
#3 - c4-judge
2024-03-15T02:10:54Z
HickupHH3 changed the severity to 2 (Med Risk)
#4 - c4-judge
2024-03-22T04:21:56Z
HickupHH3 marked the issue as duplicate of #376