Lucene search

K
code423n4Code4renaCODE423N4:2023-08-POOLTOGETHER-FINDINGS-ISSUES-120
HistoryAug 07, 2023 - 12:00 a.m.

The RngRelayAuction::rngComplete() function can be called by anyone (malicious actor) causing that the draw will be closed using a malicious random number

2023-08-0700:00:00
Code4rena
github.com
5
vulnerability details
rngcomplete function
rngauctionrelayerdirect contract
rngauctionrelayerremoteowner contract
rng results
malicious actor
randomnumber
receive the rewards

Lines of code
<https://github.com/GenerationSoftware/pt-v5-draw-auction/blob/f1c6d14a1772d6609de1870f8713fb79977d51c1/src/RngRelayAuction.sol#L154&gt;
<https://github.com/GenerationSoftware/pt-v5-draw-auction/blob/f1c6d14a1772d6609de1870f8713fb79977d51c1/src/RngRelayAuction.sol#L170&gt;

Vulnerability details

Impact

The rngComplete() function is called by the RngAuctionRelayerDirect contract or the RngAuctionRelayerRemoteOwner contract. The rngComplete() function receives the RNG results from the rng auction.

The problem here is that the rngComplete() function can be called by anyone not only the relayers. This is very dangerous because malicious actors can close draws without any restriction using their own malicious randomNumber. Additionally the malicious actor can receive the rewards.

Proof of Concept

The rngComplete() function does not have any restriction about who can call it so in the code line 154 the prizePool will close the draw using a custom number specified in the code line 132 by the malicious actor.

File: RngRelayAuction.sol
131:   function rngComplete(
132:     uint256 _randomNumber,
133:     uint256 _rngCompletedAt,
134:     address _rewardRecipient,
135:     uint32 _sequenceId,
136:     AuctionResult calldata _rngAuctionResult
137:   ) external returns (bytes32) {
138:     if (_sequenceHasCompleted(_sequenceId)) revert SequenceAlreadyCompleted();
139:     uint64 _auctionElapsedSeconds = uint64(block.timestamp &lt; _rngCompletedAt ? 0 : block.timestamp - _rngCompletedAt);
140:     if (_auctionElapsedSeconds &gt; (_auctionDurationSeconds-1)) revert AuctionExpired();
141:     // Calculate the reward fraction and set the draw auction results
142:     UD2x18 rewardFraction = _fractionalReward(_auctionElapsedSeconds);
143:     _auctionResults.rewardFraction = rewardFraction;
144:     _auctionResults.recipient = _rewardRecipient;
145:     _lastSequenceId = _sequenceId;
146: 
147:     AuctionResult[] memory auctionResults = new AuctionResult[](2);
148:     auctionResults[0] = _rngAuctionResult;
149:     auctionResults[1] = AuctionResult({
150:       rewardFraction: rewardFraction,
151:       recipient: _rewardRecipient
152:     });
153: 
154:     uint32 drawId = prizePool.closeDraw(_randomNumber);
155: 
156:     uint256 futureReserve = prizePool.reserve() + prizePool.reserveForOpenDraw();
157:     uint256[] memory _rewards = RewardLib.rewards(auctionResults, futureReserve);
158: 
159:     emit RngSequenceCompleted(
160:       _sequenceId,
161:       drawId,
162:       _rewardRecipient,
163:       _auctionElapsedSeconds,
164:       rewardFraction
165:     );
166: 
167:     for (uint8 i = 0; i &lt; _rewards.length; i++) {
168:       uint104 _reward = uint104(_rewards[i]);
169:       if (_reward &gt; 0) {
170:         prizePool.withdrawReserve(auctionResults[i].recipient, _reward);
171:         emit AuctionRewardDistributed(_sequenceId, auctionResults[i].recipient, i, _reward);
172:       }
173:     }
174: 
175:     return bytes32(uint(drawId));
176:   }

Tools used

Manual review

Recommended Mitigation Steps

Restrict only the relayers can call the rngComplete() function.

Assessed type

Access Control


The text was updated successfully, but these errors were encountered:

All reactions