Puppy Raffle

AI First Flight #1
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

high gas cost in `PuppyRaffle::enterRaffle` leads to the potential Denial of service attack(DOS)

[M-1] high gas cost in PuppyRaffle::enterRaffle leads to the potential Denial of service attack(DOS)

Description
In line Line: 87 , the attack using DOS can be done.due to grow in size of the player array , gas cost increases as the result it will lead to revert the transcation in any case by Organizer.This attack is known as DOS.

// @audit Vulnerable to DOS attack
@> for (uint256 i = 0; i < players.length - 1; i++) {
for (uint256 j = i + 1; j < players.length; j++) {
require(players[i] != players[j], "PuppyRaffle: Duplicate player");
}
}

Imapct
The for loop used in PuppyRaffle::entryRaffle for checking the duplicate addresses present in the PuppyRaffle::players array.
As the looping depends on the size of the PuppyRaffle::players array, the gas Cost increases.which can even leads to the DOS attack,
where the transaction get into error out of gas.An attacker can purposefully "stuff" the array to prevent others from entering, potentially rigging the raffle.

Proof of Concept

demonstrated the test on the basis of two senarios.

  1. when the Organizer pass PuppyRaffle::players array with 400 players in PuppyRaffle::enterRaffle

function test_for_dos() public {
address[] memory players = new address[](400);
for (uint256 i = 0; i < 400; i++) {
players[i] = address(uint160(i));
}
uint256 gasAtStart = gasleft();
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
uint256 gasAtEnd = gasleft();
console.log("gas at start is : ", gasAtStart);
console.log("gas at end left is :", gasAtEnd);
}
Ran 1 test for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] test_for_dos() (gas: 542396706)
Logs:
gas at start is : 1073648110
gas at end left is : 531326975
  1. when the Organizer pass PuppyRaffle::players array with 695 players in PuppyRaffle::enterRaffle (Crossing the Max Limit of players)

function test_for_dos() public {
address[] memory players = new address[](695);
for(uint256 i = 0; i < 695;i++){
players[i] = address(uint160(i));
}
uint256 gasAtStart = gasleft();
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
uint256 gasAtEnd = gasleft();
console.log("The value of gas is : ", gasAtStart);
console.log("The value of gas is : ", gasAtEnd);
assertEq(gasAtEnd , gasAtStart);
}
[FAIL: EvmError: Revert] test_for_dos() (gas: 1056949180)
Traces:
[1056949180] PuppyRaffleTest::test_for_dos()
|- PuppyRaffle::enterRaffle{value: 695000000000000000000}([0x0000000000000000000000000000000000000000, ..., 0x00000000000000000000000000000000000002b6])
| \- <- [OutOfGas] EvmError: OutOfGas
\- <- [Revert] EvmError: Revert

Recommended Mitagation

For Reducing the Risk of DOS there are two things to reduce Mitigate the Attack

  1. Bound the number of player to enter in game in one slot by user throguh PuppyRaffle::enterRaffle.

  2. insted of inner loop use mapping because the time complexity of using for loop to find the duplicate is O(n) and the mapping is
    O(1) with if condition.
    example:

+ mapping(address => bool) public players;
function enterRaffle(address[] memory newPlayers) public payable {
- require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
+ require(newPlayers.length <= 10 , "Max slot reached");
+ require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
- for (uint256 i = 0; i < newPlayers.length; i++) {
- players.push(newPlayers[i]);
- }
- // Check for duplicates
- // @audit DOS attack is possible over here
for (uint256 i = 0; i < players.length - 1; i++) {
- for (uint256 j = i + 1; j < players.length; j++) {
- require(players[i] != players[j], "PuppyRaffle: Duplicate player");
- }
+ require(!players[newPlayers[i]],"Duplicate Player")
+ players[newPlayers[i]] = true;
+ players.push(newPlayers[i]);
+ }
emit RaffleEnter(newPlayers);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 8 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!