NextGen - tnquanghuy0512'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: 120/243

Findings: 3

Award: $11.44

🌟 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/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L124-L130 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L134-L143

Vulnerability details

Impact

When block.timestamp == minter.getAuctionEndTime(_tokenid), user can call to both 2 function claimAuction() and cancelBid(). This one second overlapped issue can lead to malicious users use cross-function reentrancy to get double funds he/she bids. If the fund is big enough, it can drain all the fund in this contract.

Proof of Concept

The hack contract will look something like this:

contract Hack {
    bool called;
    uint256 tokenid;

    function bid(uint256 _tokenid) external payable {
        tokenid = _tokenid;
        auctionDemo.participateToAuction{value: msg.value}(_tokenid);
    }

    receive() external payable {
        if (called) return;
        called = true;

        auctionDemo.cancelAllBids(tokenid);
    }
}

Tools Used

Manual Review

    function cancelBid(uint256 _tokenid, uint256 index) public {
-       require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
+       require(block.timestamp < minter.getAuctionEndTime(_tokenid), "Auction ended");
        ...
    }
    function cancelAllBids(uint256 _tokenid) public {
-       require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
+       require(block.timestamp < minter.getAuctionEndTime(_tokenid), "Auction ended");        
        ...
    }

Assessed type

Reentrancy

#0 - c4-pre-sort

2023-11-15T04:57:43Z

141345 marked the issue as duplicate of #962

#1 - c4-judge

2023-12-04T21:42:28Z

alex-ppg marked the issue as duplicate of #1323

#2 - c4-judge

2023-12-08T17:42:33Z

alex-ppg marked the issue as partial-50

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L112

Vulnerability details

Impact

In AuctionDemo.claimAuction(), the contract will tranfer the NFT to the highest bidder of that NFT by using ERC721.safeTransferFrom() method. The issue here is, if the highest bidder is a contract and doesn't have onERC721Received() function or not return the magic number correctly, the function AuctionDemo.claimAuction() will get DOS forever. Moreover, all the bidders can't withdraw their fund using cancelBid() or cancelAllBids() because the auction end time was passed. And because this contract doesn't have an emergency function, the NFT and all the bid will get stuck in it.

Proof of Concept

    function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
        ...
        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) {
@>              IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
                (bool success, ) = payable(owner()).call{value: highestBid}("");
                emit ClaimAuction(owner(), _tokenid, success, highestBid);
            } else if (auctionInfoData[_tokenid][i].status == true) {
                (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
                emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
            } else {}
        }
    }

Tools Used

Manual Review

-   IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid);
+   IERC721(gencore).transferFrom(ownerOfToken, highestBidder, _tokenid);

Assessed type

DoS

#0 - c4-pre-sort

2023-11-17T00:09:04Z

141345 marked the issue as duplicate of #486

#1 - c4-judge

2023-12-01T22:10:20Z

alex-ppg marked the issue as not a duplicate

#2 - c4-judge

2023-12-01T22:10:35Z

alex-ppg marked the issue as duplicate of #1759

#3 - c4-judge

2023-12-08T22:07:49Z

alex-ppg marked the issue as partial-50

#4 - c4-judge

2023-12-09T00:23:12Z

alex-ppg changed the severity to 2 (Med Risk)

Awards

10.9728 USDC - $10.97

Labels

bug
2 (Med Risk)
satisfactory
duplicate-175

External Links

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L105 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L58

Vulnerability details

Impact

Notice that when block.timestamp == minter.getAuctionEndTime(_tokenid), users can call to both 2 contract participateToAuction() and claimAuction(). Because of that, this scenario can happens:

  • User A is currently the highest bidder of the NFT X, so when block.timestamp == minter.getAuctionEndTime(_tokenid), he call to claimAuction() to rightfully claim his NFT X
  • User B doesn't know the NFT X is claimed, he call to participateToAuction() to bid the highest price for NFT X when block.timestamp == minter.getAuctionEndTime(_tokenid)
  • User B realize that the NFT X is claimed, so he call to cancelBid() to withdraw his bid, but he can't because the time is already surpass minter.getAuctionEndTime(_tokenid)
  • The fund got stuck forever in the contract

Proof of Concept

Notice that user can call to both 2 function participateToAuction() and claimAuction() when block.timestamp == minter.getAuctionEndTime(_tokenid)

    function participateToAuction(uint256 _tokenid) public payable {
@>        require(msg.value > returnHighestBid(_tokenid) && block.timestamp <= minter.getAuctionEndTime(_tokenid) && minter.getAuctionStatus(_tokenid) == true);
        ...
    }
    function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
@>        require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true);
        ...
    }

Tools Used

Manual Review

    function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){
-        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);
        ...
    }

Assessed type

Other

#0 - c4-pre-sort

2023-11-14T10:28:01Z

141345 marked the issue as duplicate of #1935

#1 - c4-pre-sort

2023-11-14T14:21:38Z

141345 marked the issue as duplicate of #962

#2 - c4-judge

2023-12-02T15:32:58Z

alex-ppg marked the issue as not a duplicate

#3 - c4-judge

2023-12-02T15:34:45Z

alex-ppg marked the issue as duplicate of #1926

#4 - c4-judge

2023-12-08T18:48:14Z

alex-ppg marked the issue as satisfactory

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