AI Arena - PUSH0'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: 278/283

Findings: 1

Award: $0.04

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

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

Vulnerability details

Vulnerability details

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

Proof of concept

  1. Alice owns a fighter NFT. She doesn't like its current attributes. She wants to maximize/minimize it to fit her gameplay goals.
  2. Alice generates thousands of private keys. For each resulting account, she computes the DNA outcome, and thereby attribute outcomes, by copying the contract logic, if that account were the NFT owner and rerolls. A modern computer can do hundreds of millions of operations in one second, so this step does not take much time.
  3. Alice picks out the account that yields the most favorable fighter attributes. She transfers her NFT to that account, along with some NRN and gas fee for rerolling.
  4. From the new account, she calls reRoll(). The NFT's attribute is now favorable to Alice.
  5. She transfers the NFT back to her original account.

Alice was able to select her own fighter attributes, as opposed to randomizing it.

Impact

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:

  • On chains supported by Chainlink, you can use its VRF (Verifiable Random Number) service.
  • On other chains, the method to generate a random number may be different. However modern blockchains generally come with their own method to reliably generate a random number with full security considerations.
  • RanDAO is also a possible method.

Assessed type

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

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