hyh - ethRecipient
can cancel and create streams with lagged currentTick
, can brick StreamEscrow
#174
Labels
Will Fix
The sponsor confirmed this issue will be fixed
hyh
Medium
ethRecipient
can cancel and create streams with laggedcurrentTick
, can brick StreamEscrowSummary
ethRecipient
turning malicious can reenterforwardAll()
whenethStreamedPerTick
for the current tick was already paid, but the tick counter isn't advanced yet. This allows it receiving extra tick of streamingAlso, it can reenter
createStream()
multiple times, pushingethStreamEndingAtTick[currentTick + streamLengthInTicks]
arbitrary high and bricking StreamEscrow instreamLengthInTicks
ticksRoot Cause
Initially
ethRecipient
is set to DAO address, but later can be updated to be any independent contract or EOA. The first part, immediately adding extra tick to the streaming of the all DAO owned nouns with streams, is beneficial to the DAO as it is, the second part, drivingethStreamEndingAtTick[currentTick + streamLengthInTicks]
high, doesn't look to have any monetary benefits, but can be used as some type of griefing.forwardAll()
outbound transfer happens before state update:StreamEscrow.sol#L136-L149
forwardAll()
is public and caller can manipulate the amount of gas being forwarded toethRecipient
:StreamEscrow.sol#L303-L309
This way
ethRecipient
can callforwardAll()
with an arbitrary high amount of gas, providing the way to perform any operations desired.E.g. all the streams for the Nouns with active streams
ethRecipient
owns (or controls via other accounts) can be repeated for the current tick viacancelStream()
as it can be called from theforwardAll()
, soticksLeft
there be bloated by1
:StreamEscrow.sol#L167-L182
This way
ethRecipient
receives extra tick for all the nouns they owned and cancelled streams for:cancelStream()
is done once for each noun, butticksLeft
is greater than its correct value by1
ethRecipient
be able to create streams (added toallowedToCreateStream
in addition to the auction house contract) at some point thencreateStream()
can repeatedly reenter itself, arbitrary inflatingethStreamEndingAtTick
, essentially breaking StreamEscrow logic:StreamEscrow.sol#L112-L130
After
streamLengthInTicks - 1
ticks the tick cannot be advanced to the tick numbercurrentTick + streamLengthInTicks
asethStreamEndingAtTick[currentTick + streamLengthInTicks] > ethStreamedPerTick
:StreamEscrow.sol#L311-L317
This is not monetary beneficial for DAO, but can be used as a part of wider griefing attack
Internal pre-conditions
DAO majority driven
ethRecipient
is set to game streaming and receive delayed revenue earlyethRecipient
is manipulated as a part of some griefing attack, seeking to damage existing infrastructureExternal pre-conditions
None, the access rights are provided by default
Attack Path
Call
forwardAll()
, reenter withcancelStream()
/cancelStreams()
on receiving ether onceCall
createStream()
, reenter withcreateStream()
on receiving ether multiple times, needed to driveethStreamEndingAtTick[currentTick + streamLengthInTicks]
high enoughImpact
ethRecipient
receivesethStreamedPerTick * nounsWithStreamsOwned
extra ETHtick will not be able to be advanced to
currentTick + streamLengthInTicks
, so streaming and auctioning (due to integration) are stopped therePoC
ethRecipient
updates to entercancelStreams()
once on receiving ether, callsforwardAll()
with enough gasethRecipient
updates to entercreateStream()
several times in total, high enough to exceed futureethStreamedPerTick
, on receiving ether, callscreateStream()
with enough gasMitigation
Consider making
sendETHToTreasury()
the last operation inforwardAll()
andcreateStream()
, e.g.:StreamEscrow.sol#L136-L149
Also, since
cancelStream()
andcreateStream()
are infrequent operations, both can be madenonReentrant
The text was updated successfully, but these errors were encountered: