# Another Please ``` A smart contract system is selling DownUnderLand tickets! Can you get them all? Goal: Own all 30 tickets to DownUnderLand in your player wallet. Author: BlueAlder Estimated startup time: 90 seconds ``` # setup Siehe "Eight Five Four Five" # Source ```sol // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; /** * ______ _ _ _ _ _ * | _ \ | | | | | | | | | | * | | | |_____ ___ __ | | | |_ __ __| | ___ _ __| | __ _ _ __ __| | * | | | / _ \ \ /\ / / '_ \| | | | '_ \ / _` |/ _ \ '__| | / _` | '_ \ / _` | * | |/ / (_) \ V V /| | | | |_| | | | | (_| | __/ | | |___| (_| | | | | (_| | * |___/ \___/ \_/\_/ |_| |_|\___/|_| |_|\__,_|\___|_| \_____/\__,_|_| |_|\__,_| */ import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; contract AnotherPlease is ERC721Enumerable { uint256 public constant TICKETS_TO_GIVE_AWAY = 10; uint256 public constant PURCHASABLE_TICKETS = 20; uint256 public constant TICKET_PRICE = 10000000000000 ether; mapping(address => bool) public freeTicketReceivers; uint256 public ticketsGivenAway; error FreeTicketAlreadyClaimed(); error FreeTicketsExhausted(); error NotEnoughFunds(); error SoldOut(); constructor() ERC721("DownUnderLand Tickets", "DUCTF_ENTRY") {} modifier ticketNotClaimed() { if (freeTicketReceivers[msg.sender]) revert FreeTicketAlreadyClaimed(); _; } // The first 20 people to claim a ticket get it freeeeeeeeeeeeeeeee! function claimFreeTicket() external ticketNotClaimed { if (ticketsGivenAway >= TICKETS_TO_GIVE_AWAY) revert FreeTicketsExhausted(); _gibTicket(msg.sender); ticketsGivenAway++; freeTicketReceivers[msg.sender] = true; } // Buy a ticket to the exclusive DownUnderLand Party!!!!! // Cheap price! function buyATicket() external payable { if (msg.value < TICKET_PRICE) revert NotEnoughFunds(); _gibTicket(msg.sender); uint256 change = TICKET_PRICE - msg.value; if (change > 0) { (bool success,) = msg.sender.call{value: change}(""); require(success, "Bruh do u not want ur money back?"); } } function totalTicketsAvailable() public pure returns (uint256) { return TICKETS_TO_GIVE_AWAY + PURCHASABLE_TICKETS; } function _gibTicket(address to) internal { if (totalSupply() >= totalTicketsAvailable()) revert SoldOut(); _safeMint(to, totalSupply()); } } ``` # Analyse Ziel ist es alle 30 Tickets zu besitzen. Glücklicherweise kriegen wir die ersten 20 gratis, aber die letzten 10 sind teurer als wir es uns leisten können. Die Methode ```claimFreeTicket``` prüft erst, ob noch gratis Tickets vorhanden sind, und sendet dann das Ticket und decrementiert dann den Counter. Und hier liegt die Schwachstelle: Der Angreifer Callt schnell hintereinander die ```claimFreeTicket``` Methode. Das Übertragen der Tickets via ```_safeMint``` dauert (vermutlich eine gewisse zeit in der alle 30 If-Abfragen positiv durchlaufen werden). Wenn der Counter heruntergesetzt wird, werden wir schon alle Tickets besitzen. # Lösung #TODO