PoolTogether - Tripathi's results

A protocol for no-loss prize savings

General Information

Platform: Code4rena

Start Date: 07/07/2023

Pot Size: $121,650 USDC

Total HM: 36

Participants: 111

Period: 7 days

Judge: Picodes

Total Solo HM: 13

Id: 258

League: ETH

PoolTogether

Findings Distribution

Researcher Performance

Rank: 39/111

Findings: 2

Award: $360.73

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

19.2867 USDC - $19.29

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-431

External Links

Lines of code

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L299

Vulnerability details

Impact

setDrawManager offers Attacker to frontrun the tx which can lock drawManager role. User will have to do costly redeployment which again prone to frontrun attack if he doesn't specify drawManager role in constructor and leads to DOS .

scenarios

  1. if drawManager has not been set in constructor [DOS] this will lead to DOS as for every deployment Attacker can frontrun the setDrawManager. This will lock the drawManager role and so prizePool

  2. As in constructor there is no address check for address so invalid address will cost redeployment

Proof of Concept

see Impact

File: src/PrizePool.sol

258 constructor(
    ConstructorParams memory params
  )
    TieredLiquidityDistributor(
      params.numberOfTiers,
      params.tierShares,
      params.canaryShares,
      params.reserveShares
    )
  {
    if (unwrap(params.smoothing) >= unwrap(UNIT)) {
      revert SmoothingGTEOne(unwrap(params.smoothing));
    }
    prizeToken = params.prizeToken;
    twabController = params.twabController;
    smoothing = params.smoothing;
    claimExpansionThreshold = params.claimExpansionThreshold;
    drawPeriodSeconds = params.drawPeriodSeconds;
    _lastClosedDrawStartedAt = params.firstDrawStartsAt;

    drawManager = params.drawManager;
    if (params.drawManager != address(0)) {
      emit DrawManagerSet(params.drawManager);
    }
282  }

299  function setDrawManager(address _drawManager) external {
    if (drawManager != address(0)) {
      revert DrawManagerAlreadySet();
    }
    drawManager = _drawManager;

306    emit DrawManagerSet(_drawManager);
  }

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L258C2-L283C1

https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L299C1-L307C1

Tools Used

Manual

set the drawManager role to deployer(msg.sender) in constructor and then add a option to change setdrawManager where deployer can set drawManager to any address

Assessed type

Access Control

#0 - c4-judge

2023-07-14T22:59:58Z

Picodes marked the issue as duplicate of #356

#1 - c4-judge

2023-08-06T10:31:36Z

Picodes changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-08-06T10:32:12Z

Picodes marked the issue as satisfactory

Findings Information

🌟 Selected for report: catellatech

Also found by: Tripathi, nadin

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-423

Awards

341.4422 USDC - $341.44

External Links

Lines of code

https://github.com/PaulRBerg/prb-math/blob/df27d3d12ce12153fb166e1e310c8351210dc7ba/src/sd59x18/Math.sol#L596-L609 https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/libraries/DrawAccumulatorLib.sol#L390-L399

Vulnerability details

Impact

Protocol is highly dependent on the computation of area under the curve c(d) = −t ∗ ln(α)∗α ^ d which uses PRB-Math's Pow() function to calculate . Recently It has been found this pow() function can give inconsistent values and break the computation.

PRBMath's pow() function takes two signed integer (say a and b) and returns a**b A proper implementation of power function states that : for any a >= b and x >= 0 , a ** x >= b ** x

Simplifying this further as (a>=b)= ((a/b)>=1) and so (a/b)**x >=1 [x>=0] this pow() function doesn't follow this and gives inconsistent values.

This Mainly affects integrate function of DrawAccumulatorLib.sol which integrate from a lower value higher value for the exponential weighted average

Proof of Concept

File: prb-math/src/sd59x18/Math.sol

596: function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();

    if (xInt == 0) {
        result = yInt == 0 ? UNIT : ZERO;
    } else {
        if (yInt == uUNIT) {
            result = x;
        } else {
            result = exp2(mul(log2(x), y));
        }
    }
609: }

Test Function

function testPow() public {
uint128 high = 505456470057136353;
uint128 low = 505456461792312955;
assert(high > low);
SD59x18 exp = UD2x18.wrap(31414735).intoSD59x18();
SD59x18 highPow = high.intoSD59x18().pow(exp);
SD59x18 lowPow = low.intoSD59x18().pow(exp);
assert(SD59x18.unwrap(highPow) < SD59x18.unwrap(lowPow));
}

Root cause described by a senior watson - "in the exp2() function, bit masks are applied to multiply the result by root(2,2^-i) for each position i with a value of 1. However at Common.sol#L170, the value is incorrectly included as 0xFF00000000 instead of 0xFF000000 "

Tools Used

Manual , Foundry Testing

Ensure that calculation is accurate by adjusting the comparison value in exp2() function

Assessed type

Math

#0 - c4-judge

2023-07-14T22:37:38Z

Picodes marked the issue as duplicate of #423

#1 - Picodes

2023-07-29T15:47:02Z

Downgrading to Med as this report doesn't show how it could qualify for High severity

#2 - c4-judge

2023-08-05T21:55:56Z

Picodes changed the severity to 2 (Med Risk)

#3 - c4-judge

2023-08-05T21:56:04Z

Picodes marked the issue as selected for report

#4 - c4-judge

2023-08-07T16:42:58Z

Picodes marked the issue as satisfactory

#5 - catellaTech

2023-08-08T18:52:13Z

Hello, Picodes! While the issue with that function is real, I believe the appropriate mitigation was proposed by Obront you can see more about this in this post , as the co-founder of the project being audited is also the creator of PRBMath. Therefore, it seems out of reach for the PT team to fix the function directly, and instead, the suitable mitigation would be the one proposed by the PRBMath team after they resolved the problem with exp2(). I discussed this further in my report.

Additionally, I think this issue should be considered of high severity because even though the problem was with exp2(), there were some inconsistencies in functions like div and mul, which are heavily used in important calculations within PT. The PRBMath team has already resolved these inconsistencies in version 4.

#6 - c4-judge

2023-08-12T16:26:42Z

Picodes marked issue #423 as primary and marked this issue as a duplicate of 423

#7 - Picodes

2023-08-12T16:34:40Z

@catellaTech thank you for your comment. You are correct about the mitigation. Regarding the severity, I downgraded these issues to Med because in my opinion none of these reports properly demonstrates that this could lead to a credible loss of funds scenario. From my understanding, the issue on pow occurs only in a specific range (it is related to a bitmask error and required 50000 fuzz tests to be uncovered), so there is a significant probability that the affected zone cannot be touched by DrawAccumulatorLib.sol TierCalculationLib.sol, or that the resulting inconsistencies aren't large enough to lead to a loss of funds. Overall I think Medium severity is more appropriate here - although if we dig into it the issue might be High.

#8 - catellaTech

2023-08-12T16:39:39Z

Thanks so much for the answer! 😊👍

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter