Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auction manipulation and DoS by canceling high bids #924

Closed
c4-submissions opened this issue Nov 10, 2023 · 8 comments
Closed

Auction manipulation and DoS by canceling high bids #924

c4-submissions opened this issue Nov 10, 2023 · 8 comments
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-1323 edited-by-warden partial-50 Incomplete articulation of vulnerability; eligible for partial credit only (50%) upgraded by judge Original issue severity upgraded from QA/Gas by judge

Comments

@c4-submissions
Copy link
Contributor

c4-submissions commented Nov 10, 2023

Lines of code

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

Vulnerability details

Impact

Any auction could be manipulated and disrupted by placing a very low initial bid. Subsequently, the attacker places a really high bid and/or consistently front-run bids, dissuading other bidders from participating. Just before the auction concludes, all but the first attacker's bids are canceled and refunded, enabling the attacker to win the auction with the initially low bid, incurring minimal costs, primarily limited to gas expenses.

The current implementation of cancelAllBids() and cancelBid() allows for the cancellation of any bid, even if it happens to be the winning bid:

    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);
        ...
    function cancelAllBids(uint256 _tokenid) public {
        require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
        for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
            if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) {
          ...

Proof of Concept

Modify your fixtures hardhat/scripts/fixturesDeployment.js to add a 4th addr:

const { ethers } = require("hardhat");

// Setup test environment:
const fixturesDeployment = async () => {
  const signersList = await ethers.getSigners();
  const owner = signersList[0];
  const addr1 = signersList[1];
  const addr2 = signersList[2];
  const addr3 = signersList[3];
  const addr4 = signersList[4];

  const signers = {
    owner: owner,
    addr1: addr1,
    addr2: addr2,
    addr3: addr3,
    addr4: addr4,
  };
   ...

Use this modified nextGen.test.js that:

  1. Sets the collection
  2. Mints and Auctions an NFT to addr2
  3. Bids with a low bid as addr3 intended to win
  4. Places a blocking high bid with addr4, attacker will keep placing high bids to block other users
  5. Cancels and gets refunded for all addr4 bids before auction ends
  6. Checks thats addr3 wins the auction with the low bid

Tools Used

vs code, hardhat

Recommended Mitigation Steps

Modify the cancelAllBids() and cancelBid() to check that the highest bid is not canceled:

    function cancelBid(uint256 _tokenid, uint256 index) public {
        require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
        require(auctionInfoData[_tokenid][index].bid < returnHighestBid(_tokenid), "Can not cancel HighestBid");
    function cancelAllBids(uint256 _tokenid) public {
        require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended");
        uint256 highestBid = returnHighestBid(_tokenid);
        for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) {
            if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true && auctionInfoData[_tokenid][index].bid < highestBid) {
                auctionInfoData[_tokenid][i].status = false;
                (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}("");
                emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid);
            } else {}
        }
    }

Additionally, I would like to suggest incorporating a minBidIncreasePercentage check to ensure that a new bid is a certain percentage larger than the last high bid. This measure is intended to discourage sniping by 1 wei or front-runners.

Assessed type

DoS

@c4-submissions c4-submissions added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Nov 10, 2023
c4-submissions added a commit that referenced this issue Nov 10, 2023
@code4rena-admin code4rena-admin changed the title cancelAllBids() allows the higest bidder to cancel his bid and DoS an auction Auction manipulation and DoS by canceling High bids Nov 11, 2023
@code4rena-admin code4rena-admin changed the title Auction manipulation and DoS by canceling High bids Auction manipulation and DoS by canceling high bids Nov 13, 2023
@c4-pre-sort
Copy link

141345 marked the issue as duplicate of #962

@c4-judge c4-judge reopened this Dec 2, 2023
@c4-judge
Copy link

c4-judge commented Dec 2, 2023

alex-ppg marked the issue as not a duplicate

@c4-judge
Copy link

c4-judge commented Dec 2, 2023

alex-ppg marked the issue as duplicate of #1784

@c4-judge
Copy link

c4-judge commented Dec 7, 2023

alex-ppg marked the issue as duplicate of #1323

@c4-judge
Copy link

c4-judge commented Dec 8, 2023

alex-ppg marked the issue as partial-50

@c4-judge c4-judge added the partial-50 Incomplete articulation of vulnerability; eligible for partial credit only (50%) label Dec 8, 2023
@c4-judge
Copy link

c4-judge commented Dec 8, 2023

alex-ppg marked the issue as satisfactory

@c4-judge c4-judge added satisfactory satisfies C4 submission criteria; eligible for awards and removed partial-50 Incomplete articulation of vulnerability; eligible for partial credit only (50%) labels Dec 8, 2023
@c4-judge
Copy link

c4-judge commented Dec 8, 2023

alex-ppg marked the issue as partial-50

@c4-judge c4-judge added partial-50 Incomplete articulation of vulnerability; eligible for partial credit only (50%) and removed satisfactory satisfies C4 submission criteria; eligible for awards 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Dec 8, 2023
@c4-judge c4-judge added 3 (High Risk) Assets can be stolen/lost/compromised directly upgraded by judge Original issue severity upgraded from QA/Gas by judge labels Dec 9, 2023
@c4-judge
Copy link

c4-judge commented Dec 9, 2023

alex-ppg changed the severity to 3 (High Risk)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-1323 edited-by-warden partial-50 Incomplete articulation of vulnerability; eligible for partial credit only (50%) upgraded by judge Original issue severity upgraded from QA/Gas by judge
Projects
None yet
Development

No branches or pull requests

4 participants