NextGen - Shubham's results

Advanced smart contracts for launching generative art projects on Ethereum.

General Information

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

NextGen

Findings Distribution

Researcher Performance

Rank: 225/243

Findings: 1

Award: $0.00

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 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

Awards

0 USDC - $0.00

Labels

bug
3 (High Risk)
partial-50
duplicate-1323

External Links

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L31-L34 https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L104-L120 https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L124-L130

Vulnerability details

The auctionDemo contract holds the current auctions after the mintAndAuction functionality is called. Users can bid on a token and the highest bidder can claim the token after an auction finishes.

Users call participateToAuction() to participate & place their bid in a auction & they can only participate if their bid is higher than the highest bid for that item. Once the auction finishes, the person with the highest bid & if their status is active/true can call claimAuction() to claim their item.

However there is no restriction on what the starting price for an auction should be which makes it very easy for the attacker to win the auction & claim the prize but just giving some dust amount (1 wei) thereby causing a huge loss to the artist & organization.

Proof of Concept

Bidders call participateToAuction() & if msg.value > returnHighestBid(_tokenid) passes during the auction duration, they become the highest bidder until another buyer outbids their bid.

File: AuctionDemo

    function participateToAuction(uint256 _tokenid) public payable {
        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
        auctionInfoStru memory newBid = auctionInfoStru(msg.sender, msg.value, true);
        auctionInfoData[_tokenid].push(newBid);
    }

claimAuction() has a modifier to ensure who can call the function i.e. the highest bidder, function admin or global admin to claim the NFT which goes to the highest bidder.

File: AuctionDemo

    modifier WinnerOrAdminRequired(uint256 _tokenId, bytes4 _selector) {
      require(msg.sender == returnHighestBidder(_tokenId) || adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true, "Not allowed");
      _;
    }

Also a bidder can cancel their bid by calling cancelBid() which changes their bidding status to false.

File: AuctionDemo

    function cancelBid(uint256 _tokenid, uint256 index) public {
        require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
        require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true);
        auctionInfoData[_tokenid][index].status = false;        /// @note - status changes to false
        (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}("");
        emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid);
    }

Attack Scenario:

Although only one account is enough to carry out the attack but we are assuming attacker is using two accounts for better clarity.

  • Bob is the attacker who has two accounts X & Y with 1 wei & a huge amount respectively.
  • As soon as the auction begins, Bob calls participateToAuction() with account X having 1 wei.
  • It passes because auctionInfoData[_tokenid].length is empty & returnHighestBid(_tokenid) returns 0 in this case.
  • Bob has now entered the bid with account X.
  • Bob immediately calls participateToAuction() with account Y which has a very huge amount of money.
  • Bob now has both accounts X & Y consecutively in auctionInfoData.
  • A new bidder wants to participate but will not be able to since the highest bid amount exceeds what the user is willing to pay & so he is unable to enter the bid.
  • Bob waits till the end & as soon as the auction is about to end, he calls cancelBid() with the address of account Y.
  • Active status now changes to false for the account Y.
  • The auction ends & now there are only two bidder which are both Bob's account. One with 1 wei (which is active) & the other with a huge sum of money (whose status is now cancelled/false).
  • Bob calls claimAuction() which now checks the highest bid amount & bidder which is 1 wei & Bob respectively.
  • Function enters the loop & the 1st IF condition returns true.
  • NFT is transferred from the owner to Bob & the owner receive the highest bid amount that is 1 wei.
File: AuctionDemo

    function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
        auctionClaim[_tokenid] = true;
        uint256 highestBid = returnHighestBid(_tokenid);    /// @note - Returns 1 wei
        address ownerOfToken = IERC721(gencore).ownerOf(_tokenid);
        address highestBidder = returnHighestBidder(_tokenid);   /// @note - returns Bob
        for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) {
            if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) {    /// @note - check passes
                IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);  /// @note - NFT is received to Bob
                (bool success, ) = payable(owner()).call{value: highestBid}("");  /// @note - Owner is paid 1 wei
                emit ClaimAuction(owner(), _tokenid, success, highestBid);
        .........

Impact

Attacker can claim NFTs with dust amount causing a complete lost to the artist & the protocol.

Tools Used

Manual Review

Add a minimum starting auction amount to avoid this situation.

Assessed type

Error

#0 - c4-pre-sort

2023-11-15T10:31:10Z

141345 marked the issue as duplicate of #962

#1 - c4-judge

2023-12-02T15:13:15Z

alex-ppg marked the issue as not a duplicate

#2 - c4-judge

2023-12-02T15:16:57Z

alex-ppg marked the issue as duplicate of #1784

#3 - c4-judge

2023-12-07T11:49:36Z

alex-ppg marked the issue as duplicate of #1323

#4 - c4-judge

2023-12-08T17:27:00Z

alex-ppg marked the issue as partial-50

#5 - c4-judge

2023-12-08T17:28:20Z

alex-ppg marked the issue as satisfactory

#6 - c4-judge

2023-12-08T18:22:30Z

alex-ppg marked the issue as partial-50

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter