The SpookySwap
smart contract employs insecure sources of randomness—specifically block.timestamp
and block.prevrandao
—to determine pricing variations in its trickOrTreat
function. This approach allows attackers to predict or manipulate the random number generation, enabling them to consistently receive favorable pricing outcomes, such as always getting half-price treats or avoiding double-price tricks. Consequently, this vulnerability can lead to significant financial losses for the contract owner and undermine the fairness of the platform.
trickOrTreat
The contract's trickOrTreat
function uses the following code to generate a pseudo-random number:
Components Used:
block.timestamp
: The timestamp of the current block.
msg.sender
: The address of the caller.
nextTokenId
: A sequential token ID.
block.prevrandao
: A value intended to introduce randomness, derived from the previous block.
block.timestamp
Manipulable by Miners/Validators: Miners or validators can slightly adjust the block timestamp within acceptable limits (~15 seconds). This small adjustment can influence the outcome of the random number generation.
Predictability: Since timestamps are generally sequential and predictable, they do not add sufficient entropy.
block.prevrandao
Not Truly Random: While block.prevrandao
adds some randomness, it can be influenced, especially if a validator is malicious or colluding with an attacker.
Limited Entropy: On its own, it may not provide enough unpredictability for secure random number generation.
Combination of Predictable Variables
msg.sender
and nextTokenId
: Both are known values at the time of transaction submission.
Overall Predictability: Combining known and manipulable variables results in a random number that can be predicted or influenced by an attacker.
An attacker can:
Predict Random Outcomes: By knowing or controlling the input variables, an attacker can calculate the resulting random number before submitting a transaction.
Manipulate Block Variables: If the attacker is a miner or in collusion with one, they can adjust block.timestamp
within permissible limits to achieve a desired outcome.
Economic Exploitation: Attackers can consistently obtain half-price treats or avoid double-price tricks, resulting in financial losses for the contract owner due to reduced revenues.
Unfair Advantage: Honest users are at a disadvantage as attackers manipulate the system to their benefit.
Reputation Damage: The platform's integrity may be questioned, leading to loss of user trust and decreased adoption.
Potential for Further Attacks: Predictable randomness can open doors to other vulnerabilities, such as front-running or denial-of-service attacks.
An attacker aims to manipulate the random number generation to consistently receive the 1/1000 chance of getting a half-price treat.
Monitor the Blockchain State
Obtain the current nextTokenId
from the contract.
Retrieve the block.prevrandao
from the previous block.
Predict the Random Number
For possible values of block.timestamp
(within the miner's adjustable range), calculate the expected random number using the contract's formula.
Use known values: msg.sender
(attacker's address) and nextTokenId
.
Adjust Transaction Timing
If the attacker is a miner/validator or collaborating with one, they can adjust block.timestamp
within the allowed range to produce the desired random number.
If not, they can time their transaction submission to coincide with favorable conditions.
Submit Transaction When random == 1
When calculations show that random
will be 1
, the attacker submits the trickOrTreat
transaction.
The attacker pays half the price for the treat, exploiting the system.
It's written in the README: "We're aware of the pseudorandom nature of the current implementation. This will be replaced with Chainlink VRF in later builds." This is a known issue.
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.