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: 91/243
Findings: 3
Award: $26.18
🌟 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
Since the contract allow multiple active bid, an Attacker can place a minimum bid and another arbitrary high bid to prevent other user from participating in the auction. Then right before the auction ends, the Attacker can cancel the highest bid and win the auction with the minimum bid, essentially preventing any competition.
Run forge init
in project root
setup deployer script and test file: Gist link: link
Filepath: - script/DeployProtocol2.s.sol - test/AuctionDemoTest2.t.sol
forge test --mt testAttackerMultipleActiveBid -vv
Running 1 test for test/AuctionDemoTest2.t.sol:AuctionDemoTest2 [PASS] testAttackerMultipleActiveBid() (gas: 1279087) Logs: 9999999999999999999999 Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.57ms Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
Manual code review, Forge
Other
#0 - c4-pre-sort
2023-11-20T15:31:11Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-02T15:12:36Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-02T15:15:32Z
alex-ppg marked the issue as duplicate of #1784
#3 - c4-judge
2023-12-07T11:50:19Z
alex-ppg marked the issue as duplicate of #1323
#4 - c4-judge
2023-12-08T17:22:23Z
alex-ppg marked the issue as partial-25
#5 - c4-judge
2023-12-08T17:27:57Z
alex-ppg marked the issue as satisfactory
#6 - c4-judge
2023-12-08T18:06:05Z
alex-ppg marked the issue as partial-25
#7 - c4-judge
2023-12-09T00:20:29Z
alex-ppg changed the severity to 3 (High Risk)
🌟 Selected for report: bird-flu
Also found by: 00decree, 0xAadi, AS, Audinarey, DeFiHackLabs, Eigenvectors, Fitro, Hama, Kaysoft, Krace, REKCAH, SovaSlava, The_Kakers, Viktor_Cortess, cartlex_, degensec, devival, evmboi32, funkornaut, jacopod, openwide, peanuts, rotcivegaf, smiling_heretic, xAriextz, xiao
25.2356 USDC - $25.24
Invariant the owner of the token will receive the funds
broken, implementation is sending the fund to owner()
which will be the address that deployed AuctionDemo.sol. The fund will not be at direct risk, since the address belongs to the protocol will be receiving the fund.
Run forge init
in project root
setup deployer script and test file: Gist link: link
Filepath: - script/DeployProtocol2.s.sol - test/AuctionDemoTest2.t.sol
forge test --mt testAuctionTokenOwner -vv
owner()
instead of token ownerRunning 1 test for test/AuctionDemoTest2.t.sol:AuctionDemoTest2 [PASS] testAuctionTokenOwner() (gas: 1205318) Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.41ms Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
Manual Review, Forge
Replace owner()
with ownerOfToken
File: AuctionDemo.sol - 168: (bool success, ) = payable(owner()).call{value: highestBid}(""); - 169: emit ClaimAuction(owner(), _tokenid, success, highestBid); + 168: (bool success, ) = payable(ownerOfToken).call{value: highestBid}(""); + 169: emit ClaimAuction(ownerOfToken, _tokenid, success, highestBid);
Context
#0 - c4-pre-sort
2023-11-20T15:32:00Z
141345 marked the issue as duplicate of #245
#1 - c4-judge
2023-12-08T22:27:28Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: The_Kakers
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0xJuda, 0x_6a70, 0xarno, 0xpiken, Arabadzhiev, Bauchibred, BugsFinder0x, BugzyVonBuggernaut, ChrisTina, DeFiHackLabs, Delvir0, HChang26, Haipls, Jiamin, Juntao, KupiaSec, Madalad, Neon2835, Nyx, Ocean_Sky, SpicyMeatball, Talfao, Taylor_Webb, Timenov, Tricko, ZdravkoHr, _eperezok, alexxander, amaechieth, bdmcbri, bronze_pickaxe, circlelooper, crunch, cu5t0mpeo, dimulski, fibonacci, funkornaut, immeas, ke1caM, lsaudit, nuthan2x, r0ck3tz, rotcivegaf, spark, tnquanghuy0512, twcctop, xeros
0.9407 USDC - $0.94
Attacker can participate auction through a smart contract that did not implement ERC721Receiver
, then claimAuction()
will revert with error ERC721: transfer to non ERC721Receiver implementer
.
ALL the auction bid fund will be permanently loss.
Run forge init
in project root
setup deployer script and test file: Gist link to all files: link
Filepath: - test/mock/Attacker.sol - script/DeployProtocol.s.sol - test/AuctionDemoTest.t.sol
forge test --mt testMintAndAuction -vv
[â ¢] Compiling... No files changed, compilation skipped Running 1 test for test/AuctionDemoTest.t.sol:AuctionDemoTest [FAIL. Reason: Assertion failed.] testMintAndAuction() (gas: 1626277) Logs: Error: a == b not satisfied [uint] Left: 9000000000000000000 Right: 10000000000000000000 Error: a == b not satisfied [uint] Left: 8000000000000000000 Right: 10000000000000000000 Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 5.30ms Ran 1 test suites: 0 tests passed, 1 failed, 0 skipped (1 total tests) Failing tests: Encountered 1 failing test in test/AuctionDemoTest.t.sol:AuctionDemoTest [FAIL. Reason: Assertion failed.] testMintAndAuction() (gas: 1626277)
Manual Code Review, Forge
ERC721Receiver
implemented.function participateToAuction(uint256 _tokenid) public payable { require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true); + if (isContract(msg.sender)) { + // The address is a contract, now check if it supports ERC721Receiver + ERC165 erc165 = ERC165(msg.sender); + require(erc165.supportsInterface(0x150b7a02), "Contract did not support ERC721Receiver"); // ERC721Receiver's interface ID + } auctionInfoStru memory newBid = auctionInfoStru(msg.sender, msg.value, true); auctionInfoData[_tokenid].push(newBid); } + function isContract(address _address) public view returns (bool) { + uint256 size; + assembly { + size := extcodesize(_address) + } + return size > 0; + }
selfdestruct
or bypass extcodesize()
check and lead to same issue, so it is recommended to implement the withdrawal pattern for participant refund and winner claiming. This lays the burden of proof on the refund/token receiver.function auctionRefundWithdraw(uint256 _tokenid) public { // if auctionEnded && !claimed && msg.sender == participating user // participating user withdrawing their OWN refund only } function auctionWinnerClaim(uint256 _tokenid) public { // if auctionEnded && !claimed && msg.sender == winner/highest bidder // auction Winner claiming their token }
function auctionProtocolFeeWithdraw(uint256 _tokenid) public{ // if auctionEnded && !claimed && msg.sender == admin // protocol admin withdraw the winning auction bid }
ETH-Transfer
#0 - c4-pre-sort
2023-11-20T15:31:42Z
141345 marked the issue as duplicate of #486
#1 - c4-judge
2023-12-01T22:36:13Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-01T22:36:31Z
alex-ppg marked the issue as duplicate of #1759
#3 - c4-judge
2023-12-08T22:14:07Z
alex-ppg marked the issue as satisfactory
#4 - c4-judge
2023-12-09T00:23:12Z
alex-ppg changed the severity to 2 (Med Risk)