Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Invalid

The `ScoreBoard:SetPrediction` function allows `players` to change prediction of a match when results have been updated by the `organizer`, which leads to result being gamed

Summary

The ScoreBoard:SetPrediction function allows players to change the prediction of a match when results have been updated by the organizer, which leads to result being gamed.

Vulnerability Details

According the rules of the system it says After the end of each match the Organizer will enter the match result and ScoreBoard:results state variable even though it is private, it can still be queried from the blockchain to get the updated results and the Player can call the ScoreBoard:SetPrediction function to change their results thereby cheating the system.

Impact

A player can always win all prediction rigging the system leading to loss of funds.

Proof of Concepts
Here is a test to proof it can be gameed, add to the test file

function test_ResultsCanGamed() public {
vm.startPrank(stranger);
vm.deal(stranger, 0.0003 ether);
vm.stopPrank();
vm.warp(2);
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
0,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(organizer);
scoreBoard.setResult(0, ScoreBoard.Result.First);
vm.stopPrank();
// read values from vm
uint256 S_RESULT_STORAGE_SLOT_VALUE = 2;
bytes32 slotData = vm.load(
address(scoreBoard),
bytes32(S_RESULT_STORAGE_SLOT_VALUE)
);
uint8 readValues = abi.decode(abi.encodePacked(slotData), (uint8));
console.log(readValues);
vm.warp(3);
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
0,
ScoreBoard.Result(readValues)
);
vm.stopPrank();
assertEq(scoreBoard.getPlayerScore(stranger), 2);
}

Tools Used

  • Foundry

Recommendations

Here is a possible fix to the ScoreBoard:SetPrediction function.

function setPrediction(
address player,
uint256 matchNumber,
Result result
) public {
+ if(results[matchNumber] != Result.Pending){
+ revert ScoreBoard__MatchEnded;
+ }
if (block.timestamp <= START_TIME + matchNumber * 68400 - 68400)
playersPredictions[player].predictions[matchNumber] = result;
playersPredictions[player].predictionsCount = 0;
for (uint256 i = 0; i < NUM_MATCHES; ++i) {
if (
playersPredictions[player].predictions[i] != Result.Pending &&
playersPredictions[player].isPaid[i]
) ++playersPredictions[player].predictionsCount;
}
}
Updates

Lead Judging Commences

NightHawK Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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