Platform: Code4rena
Start Date: 30/10/2023
Pot Size: $49,250 USDC
Total HM: 14
Participants: 243
Period: 14 days
Judge: 0xsomeone
Id: 302
League: ETH
Rank: 132/243
Findings: 2
Award: $5.49
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: smiling_heretic
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0x656c68616a, 0xAadi, 0xAleko, 0xAsen, 0xDetermination, 0xJuda, 0xMAKEOUTHILL, 0xMango, 0xMosh, 0xSwahili, 0x_6a70, 0xarno, 0xgrbr, 0xpiken, 0xsagetony, 3th, 8olidity, ABA, AerialRaider, Al-Qa-qa, Arabadzhiev, AvantGard, CaeraDenoir, ChrisTina, DanielArmstrong, DarkTower, DeFiHackLabs, Deft_TT, Delvir0, Draiakoo, Eigenvectors, Fulum, Greed, HChang26, Haipls, Hama, Inference, Jiamin, JohnnyTime, Jorgect, Juntao, Kaysoft, Kose, Kow, Krace, MaNcHaSsS, Madalad, MrPotatoMagic, Neon2835, NoamYakov, Norah, Oxsadeeq, PENGUN, REKCAH, Ruhum, Shubham, Silvermist, Soul22, SovaSlava, SpicyMeatball, Talfao, TermoHash, The_Kakers, Toshii, TuringConsulting, Udsen, VAD37, Vagner, Zac, Zach_166, ZdravkoHr, _eperezok, ak1, aldarion, alexfilippov314, alexxander, amaechieth, aslanbek, ast3ros, audityourcontracts, ayden, bdmcbri, bird-flu, blutorque, bronze_pickaxe, btk, c0pp3rscr3w3r, c3phas, cartlex_, cccz, ciphermarco, circlelooper, crunch, cryptothemex, cu5t0mpeo, darksnow, degensec, dethera, devival, dimulski, droptpackets, epistkr, evmboi32, fibonacci, gumgumzum, immeas, innertia, inzinko, jasonxiale, joesan, ke1caM, kimchi, lanrebayode77, lsaudit, mahyar, max10afternoon, merlin, mrudenko, nuthan2x, oakcobalt, openwide, orion, phoenixV110, pontifex, r0ck3tz, rotcivegaf, rvierdiiev, seeques, shenwilly, sl1, slvDev, t0x1c, tallo, tnquanghuy0512, tpiliposian, trachev, twcctop, vangrim, volodya, xAriextz, xeros, xuwinnie, y4y, yobiz, zhaojie
0 USDC - $0.00
In the AuctionDemo a malicious bidder can prevent others from bidding by placing a very large bid at the start, then cancelling the bid at the deadline. Others users are not able to bid because they must place a higher bid than the current highest bid, which is now much higher than it should be.
This is done in the following steps:
It is worth noting that the attacker doesn't need to do step 3. This is important as it means that they can place a high bid that blocks the auction at any time even if they don't have the intention of winning the auction.
In this example we can assume the NFT is worth roughly 1 ETH
// attacker places a very high bid at the start of the auction vm.startPrank(attacker); auction.participateToAuction{value: 100 ether}(tokenIndex); // advance to the end of the auction vm.warp(block.timestamp + 1000); // attacker cancels the bid auction.cancelBid(tokenIndex, 0); // attacker places smallest possible bid auction.participateToAuction{value: 1}(tokenIndex);
Foundry
One of the ways to mitigate this would be to allow people to bid even if they are not the highest bid. An alternative would be to not allow the cancelling of bids.
DoS
#0 - c4-pre-sort
2023-11-15T14:48:06Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-02T15:13:19Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-02T15:17:06Z
alex-ppg marked the issue as duplicate of #1784
#3 - c4-judge
2023-12-07T11:49:33Z
alex-ppg marked the issue as duplicate of #1323
#4 - c4-judge
2023-12-08T17:27:14Z
alex-ppg marked the issue as partial-50
#5 - c4-judge
2023-12-08T17:28:22Z
alex-ppg marked the issue as satisfactory
#6 - c4-judge
2023-12-08T18:23:56Z
alex-ppg marked the issue as partial-50
🌟 Selected for report: smiling_heretic
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0x656c68616a, 0xAadi, 0xAleko, 0xAsen, 0xDetermination, 0xJuda, 0xMAKEOUTHILL, 0xMango, 0xMosh, 0xSwahili, 0x_6a70, 0xarno, 0xgrbr, 0xpiken, 0xsagetony, 3th, 8olidity, ABA, AerialRaider, Al-Qa-qa, Arabadzhiev, AvantGard, CaeraDenoir, ChrisTina, DanielArmstrong, DarkTower, DeFiHackLabs, Deft_TT, Delvir0, Draiakoo, Eigenvectors, Fulum, Greed, HChang26, Haipls, Hama, Inference, Jiamin, JohnnyTime, Jorgect, Juntao, Kaysoft, Kose, Kow, Krace, MaNcHaSsS, Madalad, MrPotatoMagic, Neon2835, NoamYakov, Norah, Oxsadeeq, PENGUN, REKCAH, Ruhum, Shubham, Silvermist, Soul22, SovaSlava, SpicyMeatball, Talfao, TermoHash, The_Kakers, Toshii, TuringConsulting, Udsen, VAD37, Vagner, Zac, Zach_166, ZdravkoHr, _eperezok, ak1, aldarion, alexfilippov314, alexxander, amaechieth, aslanbek, ast3ros, audityourcontracts, ayden, bdmcbri, bird-flu, blutorque, bronze_pickaxe, btk, c0pp3rscr3w3r, c3phas, cartlex_, cccz, ciphermarco, circlelooper, crunch, cryptothemex, cu5t0mpeo, darksnow, degensec, dethera, devival, dimulski, droptpackets, epistkr, evmboi32, fibonacci, gumgumzum, immeas, innertia, inzinko, jasonxiale, joesan, ke1caM, kimchi, lanrebayode77, lsaudit, mahyar, max10afternoon, merlin, mrudenko, nuthan2x, oakcobalt, openwide, orion, phoenixV110, pontifex, r0ck3tz, rotcivegaf, rvierdiiev, seeques, shenwilly, sl1, slvDev, t0x1c, tallo, tnquanghuy0512, tpiliposian, trachev, twcctop, vangrim, volodya, xAriextz, xeros, xuwinnie, y4y, yobiz, zhaojie
0 USDC - $0.00
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L124 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L134
In the AuctionDemo contract the winner of the auction can claim their NFT and cancel their bid. This means that they can get the NFT for free.
This is done in the following steps, at the end of the auction(block.timestamp == minter.getAuctionEndTime(_tokenid)):
This attack does require the amount of ETH in the contract to be greater than or equal to the winning bid(before the attacker places the bid). This should easiely be possible with other auctions happening.
It also has the effect of there not being enough ETH left for the other auctions meaning that some of the bidders will not recieve their refund and the owner may not recieve the winning bid.
In this POC we assume there are other auctions happening and that the sum of their bids is greater than 1 ETH This ensures there is enough balance for the attacker to cancel their bid
// advance to the end of the auction(block.timestamp == minter.getAuctionEndTime(_tokenid)) vm.warp(block.timestamp + 1000); // attacker places a bid vm.startPrank(attacker); auction.participateToAuction{value: 1 ether}(tokenIndex); // attacker claims their nft auction.claimAuction(tokenIndex); // attacker cancels the bid auction.cancelBid(tokenIndex, 0); vm.stopPrank();
Foundry
Update claimAuction() so that it can only be called after the end of the auction and not at the end.
This ensures that claimAuction() and cancelBid()/cancelAllBids() are not able to be called in the same transaction
- require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); + require(block.timestamp > minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
Timing
#0 - c4-pre-sort
2023-11-15T10:25:25Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-01T16:04:04Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-01T16:04:12Z
alex-ppg marked the issue as duplicate of #1788
#3 - c4-judge
2023-12-08T18:21:53Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: HChang26
Also found by: 0x3b, 0xMAKEOUTHILL, 0xSwahili, 0xarno, ABA, DeFiHackLabs, Eigenvectors, Haipls, Kow, MrPotatoMagic, Neon2835, Nyx, Zac, alexfilippov314, ayden, c3phas, immeas, innertia, lsaudit, merlin, mojito_auditor, oakcobalt, ohm, oualidpro, peanuts, phoenixV110, sces60107, t0x1c, tnquanghuy0512, ubl4nk, volodya, xAriextz
5.4864 USDC - $5.49
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L104 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L57
The highest bidder can frontrun anyone that waits until the end of the auction to bid(block.timestamp == minter.getAuctionEndTime(_tokenid)).
The current highest bidder can frontrun any bids at the deadline with a call to claimAuction(). The bids will still succeed and the new highest bidder will not be able to refund and will not be able to claim their NFT.
In this example Alice is the highest bidder and Bob waits until the end to bid.
// Alice places a bid of 1 ether vm.prank(alice); auction.participateToAuction{value: 1 ether}(tokenIndex);
Advance to the end of the auction
2a. Bob places a bid at the deadline
// Bob places a bid of 2 ether vm.prank(bob); auction.participateToAuction{value: 2 ether}(tokenIndex);
2b. Alice frontruns bob with a call to claimAuction()
vm.prank(alice); auction.claimAuction(tokenIndex);
Alice has recieved the NFT Bob has not recieved the NFT and has no way to refund/cancel his bid
Foundry
It should not be possible to bid at the same time as calling claimAuction()
To solve this we can change claimAuction so that it can only be called after the end of the auction and not at the end.
- require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); + require(block.timestamp > minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
Timing
#0 - c4-pre-sort
2023-11-15T09:01:04Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-02T15:33:31Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-02T15:35:42Z
alex-ppg marked the issue as duplicate of #1926
#3 - c4-judge
2023-12-08T18:52:18Z
alex-ppg marked the issue as partial-50
#4 - c4-judge
2023-12-09T00:21:41Z
alex-ppg changed the severity to 2 (Med Risk)