Skip to content

Latest commit

 

History

History
104 lines (74 loc) · 4.71 KB

021.md

File metadata and controls

104 lines (74 loc) · 4.71 KB

Scruffy Chartreuse Wolverine

High

{A Malicious Bidder} will {Indefinitely Extend Auctions} {for Other Bidders}

Summary

The unrestricted timeBuffer mechanism in the createBid function will cause auctions to be perpetually extended for other bidders as a malicious bidder will exploit the time buffer to continuously extend auctions, preventing legitimate participants from winning.

/**
     * @notice Create a bid for a Noun, with a given amount.
     * @dev This contract only accepts payment in ETH.
     */
    function createBid(uint256 nounId) external payable override {
        createBid(nounId, 0);
    }

    /**
     * @notice Create a bid for a Noun, with a given amount.
     * @param nounId id of the Noun to bid on
     * @param clientId the client which facilitate this action
     * @dev This contract only accepts payment in ETH.
     */
    function createBid(uint256 nounId, uint32 clientId) public payable override {
        INounsAuctionHouseV2.AuctionV2 memory _auction = auctionStorage;

        (uint192 _reservePrice, uint56 _timeBuffer, uint8 _minBidIncrementPercentage) = (
            reservePrice,
            timeBuffer,
            minBidIncrementPercentage
        );

        require(_auction.nounId == nounId, 'Noun not up for auction');
        require(block.timestamp < _auction.endTime, 'Auction expired');
        require(msg.value >= _reservePrice, 'Must send at least reservePrice');
        require(
            msg.value >= _auction.amount + ((_auction.amount * _minBidIncrementPercentage) / 100),
            'Must send more than last bid by minBidIncrementPercentage amount'
        );

        auctionStorage.clientId = clientId;
        auctionStorage.amount = uint128(msg.value);
        auctionStorage.bidder = payable(msg.sender);

        // Extend the auction if the bid was received within `timeBuffer` of the auction end time
        bool extended = _auction.endTime - block.timestamp < _timeBuffer;

        emit AuctionBid(_auction.nounId, msg.sender, msg.value, extended);
        if (clientId > 0) emit AuctionBidWithClientId(_auction.nounId, msg.value, clientId);

        if (extended) {
            auctionStorage.endTime = _auction.endTime = uint40(block.timestamp + _timeBuffer);
            emit AuctionExtended(_auction.nounId, _auction.endTime);
        }

        address payable lastBidder = _auction.bidder;

        // Refund the last bidder, if applicable
        if (lastBidder != address(0)) {
            _safeTransferETHWithFallback(lastBidder, _auction.amount);
        }
    }

Root Cause

The choice to implement an unbounded timeBuffer in the createBid function is flawed. This design allows auctions to be extended indefinitely by permitting bidders to place bids within the timeBuffer period without imposing any limits on the number of extensions.

Internal pre-conditions

  1. An auction is currently active with a defined endTime.
  2. A malicious bidder can place bids repeatedly within the timeBuffer period to extend the auction's duration.
  3. Each new bid meets or exceeds the minBidIncrementPercentage requirement over the previous bid.
  4. The contract does not impose a maximum number of allowed extensions per auction.

External pre-conditions

The attacker has access to automated bots capable of monitoring auction end times and placing bids precisely within the timeBuffer. The contract owner has not set any restrictions or limits on auction extensions.

Attack Path

  1. The attacker deploys a Malicious Bidder Bot.
  2. The attacker deploys the MaliciousBidderBot contract, targeting the NounsAuctionHouseV2 or NounsAuctionHouseV3 contract.
  3. The bot places an initial bid that meets or exceeds the reservePrice and minBidIncrementPercentage, becoming the highest bidder.
  4. The bot continuously monitors the auction's endTime.
  5. As the auction approaches its endTime (within the timeBuffer period), the bot places another bid, triggering the extension of the auction's endTime by timeBuffer.
  6. The bot continues to place bids within the timeBuffer period, perpetually extending the auction and preventing it from settling.

Impact

Legitimate bidders are unable to win auctions, leading to loss of participation and potential financial losses. The auction cadence is disrupted, potentially leading to delays in asset distribution and complications in system state management.

PoC

No response

Mitigation

  1. Introduce a maximum number of allowed extensions per auction (e.g., a maximum of 5 extensions).
  2. Enforce a cooldown period after each extension to prevent back-to-back last-second bids