Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

DOS in withdraw function if `maxScore` and `totalPositivePoints` is zero leads to stuck funds.

Summary

DOS in withdraw function if maxScore and totalPositivePoints is zero leads to stuck funds.

Vulnerability Details

ThePredicter::withdraw function lets players withdraw their funds after all the matches have been played and allocates rewards to the players depending on the prediction of the players. it uses maxScore to keep track of the maximum number of points by any player and totalPositivePoints to keep track of the total number of positive points of all players. If the maxScore is less than zero the totalPositivePoints will be zero and all the players will be given back their entrance fee.
If the maxScore is greater than zero the totalPositivePoints will be greater than zero and the player who is withdrawing has points greater than zero their reward is calculated and sent to them.

Proof of Concept:
Add code to test file

function test_rewardDistributionDOS() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
vm.startPrank(stranger);
vm.deal(stranger, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger2);
vm.deal(stranger2, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger3);
vm.deal(stranger3, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
thePredicter.approvePlayer(stranger2);
thePredicter.approvePlayer(stranger3);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(stranger3);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(organizer);
scoreBoard.setResult(0, ScoreBoard.Result.First);
scoreBoard.setResult(1, ScoreBoard.Result.First);
scoreBoard.setResult(2, ScoreBoard.Result.First);
scoreBoard.setResult(3, ScoreBoard.Result.First);
scoreBoard.setResult(4, ScoreBoard.Result.First);
scoreBoard.setResult(5, ScoreBoard.Result.First);
scoreBoard.setResult(6, ScoreBoard.Result.First);
scoreBoard.setResult(7, ScoreBoard.Result.First);
scoreBoard.setResult(8, ScoreBoard.Result.First);
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.withdrawPredictionFees();
vm.stopPrank();
//[FAIL. Reason: panic: division or modulo by zero (0x12)]
vm.startPrank(stranger);
thePredicter.withdraw();
vm.stopPrank();
}

Impact

If the maxScore is zero the totalPositivePoints will be zero and the reward calculation will result in a calculation by zero hence reverting which will mean none player will be able to withdraw and the funds will be stuck in the contract.

Tools Used

Manual Analysis

Recommendations

Add logic for when the `maxScore` and `totalPositivePoints` are zero.

Updates

Lead Judging Commences

NightHawK Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Possible maxScore of zero is not accounted

The checks related to maxScore do not account possible maxScore of zero leading to stuck funds or a division by zero error.

Support

FAQs

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