Platform: Code4rena
Start Date: 02/08/2023
Pot Size: $42,000 USDC
Total HM: 13
Participants: 45
Period: 5 days
Judge: hickuphh3
Total Solo HM: 5
Id: 271
League: ETH
Rank: 3/45
Findings: 2
Award: $2,768.02
🌟 Selected for report: 1
🚀 Solo Findings: 1
🌟 Selected for report: nadin
2291.9874 USDC - $2,291.99
https://github.com/GenerationSoftware/pt-v5-cgda-liquidator/blob/7f95bcacd4a566c2becb98d55c1886cadbaa8897/src/libraries/ContinuousGDA.sol#L34-L36 https://github.com/GenerationSoftware/pt-v5-cgda-liquidator/blob/7f95bcacd4a566c2becb98d55c1886cadbaa8897/src/libraries/ContinuousGDA.sol#L64 https://github.com/GenerationSoftware/pt-v5-cgda-liquidator/blob/7f95bcacd4a566c2becb98d55c1886cadbaa8897/src/libraries/ContinuousGDA.sol#L85-L87 https://github.com/PaulRBerg/prb-math/blob/5959ef59f906d689c2472ed08797872a1cc00644/src/sd59x18/Math.sol#L168-L181
ContinuousGDA.sol
inherits a version of PRB Math
that contains a vulnerability in the SD59x18.exp()
function, which can be reverted on hugely negative numbers. SD59x18.exp()
is used for calculations in ContinuousGDA.sol#purchasePrice()
, ContinuousGDA.sol#purchaseAmount()
and ContinuousGDA.sol#computeK()
. Recently, the creators of the PRBMath
have acknowledged this situation. Here is the corresponding link. This issue should be proactively corrected by PoolTogether
to avoid unexpected results that corrupt the protocol's computation flow.
There are 05 instances of this issue: see here
File: ContinuousGDA.sol 34: topE = topE.exp().sub(ONE); 36: bottomE = bottomE.exp(); 64: SD59x18 exp = _decayConstant.mul(_timeSinceLastAuctionStart).exp(); 85: SD59x18 eValue = exponent.exp(); 87: SD59x18 denominator = (_decayConstant.mul(_purchaseAmount).div(_emissionRate)).exp().sub(ONE);
Proof of the bug acknowledgment by the creator of the PRBMath
SD59x18.exp()
correctly returns 0 for inputs less than (roughly) -41.45e18, however it starts to throw PRBMath_SD59x18_Exp2_InputTooBig
when the input gets hugely negative. This is because of the unchecked multiplication in exp()
overflowing into positive values: see here
function exp(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); // This check prevents values greater than 192e18 from being passed to {exp2}. if (xInt > uEXP_MAX_INPUT) { revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x); } unchecked { // Inline the fixed-point multiplication to save gas. int256 doubleUnitProduct = xInt * uLOG2_E; // <== overflow result = exp2(wrap(doubleUnitProduct / uUNIT)); } }
Manual Review and Proof of the bug acknowledgment by the creator of the PRBMath
A potential fix would be to compare the input with the smallest (most negative) number that can be safely multiplied by uLOG2_E
, and return 0 if it's smaller. Alternatively, exp()
could return 0 for inputs smaller than -41.45e18, which are expected to be truncated to zero by exp2()
anyway.
Math
#0 - c4-pre-sort
2023-08-08T03:17:18Z
raymondfam marked the issue as primary issue
#1 - c4-pre-sort
2023-08-08T05:26:21Z
raymondfam marked the issue as high quality report
#2 - c4-sponsor
2023-08-10T19:50:31Z
asselstine marked the issue as sponsor confirmed
#3 - c4-judge
2023-08-14T09:47:52Z
HickupHH3 marked the issue as selected for report
#4 - HickupHH3
2023-08-14T09:51:10Z
Would have been nice to see a concrete example where the input < -41.45e18.
Given that the pricing formula parameters are determined by the liquidation pair creator, it is a possibility to achieve this condition and have this bug invoked.
🌟 Selected for report: MohammedRizwan
Also found by: MohammedRizwan, nadin, ptsanev
476.0281 USDC - $476.03
Allowing creation of new LiquidationPairs
by Re-org attack
may adversely affect pricing in LiquidationPair.sol
contracts.
The LiquidationPairFactory.sol#createPair()
function deploys a new LiquidationPair
using the create
, where the address derivation depends only on the arguments passed.
At the same time, some of the chains like Arbitrum
and Polygon
are suspicious of the reorg attack.
LiquidationPairFactory.sol#createPair()
File: LiquidationPairFactory.sol function createPair( ILiquidationSource _source, address _tokenIn, address _tokenOut, uint32 _periodLength, uint32 _periodOffset, uint32 _targetFirstSaleTime, SD59x18 _decayConstant, uint112 _initialAmountIn, uint112 _initialAmountOut, uint256 _minimumAuctionAmount ) external returns (LiquidationPair) { LiquidationPair _liquidationPair = new LiquidationPair( // @audit-issue Reorg Attack _source, _tokenIn, _tokenOut, _periodLength, _periodOffset, _targetFirstSaleTime, _decayConstant, _initialAmountIn, _initialAmountOut, _minimumAuctionAmount ); allPairs.push(_liquidationPair); deployedPairs[_liquidationPair] = true; emit PairCreated( _liquidationPair, _source, _tokenIn, _tokenOut, _periodLength, _periodOffset, _targetFirstSaleTime, _decayConstant, _initialAmountIn, _initialAmountOut, _minimumAuctionAmount ); return _liquidationPair; }
Optimistic rollups (Optimism/Arbitrum) are also suspect to reorgs since if someone finds a fraud the blocks will be reverted, even though the user receives a confirmation. Can refer this an issue previously report here to have more understanding about it.
Manual review and previously report here
Deploy createPair() via create2
with salt
.
Other
#0 - c4-pre-sort
2023-08-07T23:46:51Z
raymondfam marked the issue as primary issue
#1 - c4-sponsor
2023-08-10T19:58:08Z
asselstine marked the issue as sponsor confirmed
#2 - HickupHH3
2023-08-12T08:39:54Z
Allowing this to remain as medium because it "adversely affect pricing". Would be nice to see more concrete proof though:
where the address derivation depends only on the arguments passed.
true for create2
, not for create
, so I suppose one could pass in less favourable arguments.
#3 - c4-judge
2023-08-12T08:39:58Z
HickupHH3 marked the issue as selected for report
#4 - stalinMacias
2023-08-14T19:24:29Z
Hey @HickupHH3 Can I ask how is the reorg-attack causing any harm to the protocol? The warden's statement " may adversely affect pricing in LiquidationPair.sol contracts." is very vague and there is not proof of how the pricing is impacted.
As for the previous report that the warden used as a reference for his finding, I think the reorg attack is valid in that protocol because the deployed contracts have a payable constructor that is expecting to receive ETH, and if the reorg attack happens then the ETH sent by the deployer is lost, but in this case, for this protocol, the deployed contracts are not payable, so what's the incentive to cause a "reorg-attack", and more important, what are the consequences?
IMHO, if there is no proof about how the pricing may be affected, this should be assessed as a Q/A
#5 - HickupHH3
2023-08-15T03:02:05Z
@stalinMacias It's not so much causing a re-org attack, but taking advantage of it.
Because create
is used, you could theoretically deploy with different params but have the same contract address in this scenario, then re-send (replay) the liquidator's tx to auction for more / less POOL tokens.
I shouldn't be doing the work to reason it out though, burden of proof lies with the wardens. None have sufficient justification to warrant the medium severity.
Downgrading to QA.
#6 - c4-judge
2023-08-15T03:02:15Z
HickupHH3 changed the severity to QA (Quality Assurance)
#7 - c4-judge
2023-08-15T03:02:34Z
HickupHH3 marked the issue as not selected for report
#8 - c4-judge
2023-08-15T03:02:39Z
HickupHH3 marked the issue as grade-c
#9 - Nadinnnn
2023-08-15T07:06:18Z
I agree with this issue being downgraded to QA, but still having an attack like you helped us understand more about how this issue can be exploited. The sponsor has also confirmed this issue and I think they will fix it. So I think this case can get grade A.
#10 - c4-judge
2023-08-17T14:50:07Z
This previously downgraded issue has been upgraded by HickupHH3
#11 - c4-judge
2023-08-17T14:50:17Z
HickupHH3 marked issue #31 as primary and marked this issue as a duplicate of 31
#12 - c4-judge
2023-08-17T15:02:20Z
HickupHH3 marked the issue as satisfactory
#13 - c4-judge
2023-08-17T15:04:12Z
HickupHH3 marked the issue as not a duplicate
#14 - c4-judge
2023-08-17T15:04:28Z
HickupHH3 changed the severity to QA (Quality Assurance)
#15 - c4-judge
2023-08-17T15:04:40Z
This previously downgraded issue has been upgraded by HickupHH3
#16 - c4-judge
2023-08-17T15:04:40Z
This previously downgraded issue has been upgraded by HickupHH3
#17 - c4-judge
2023-08-17T15:04:50Z
HickupHH3 marked the issue as duplicate of #31