Mr Steal Yo Crypto - Jpeg Sniper

Disclaimer

This is not a walkthrough of every contract or code of the challenge. I am sharing my notes and resources I have used to complete this challenge, as well as some lessons I think are useful to take away after completing the challenge. I highly recommend you finish the challenge yourself first and only use this as additional content.

Notes

  • BaseLaunchpegNFT is basically an ERC721 ownable token that uses the counters contract to track the number of NFTs for functions that return the total supply or for easily minting unique id NFTs.

  • The contract declares a bunch of state variables that later get initialized in the constructor, nothing of concern there except maybe the salePrice state variable that is never initialized, which means that its 0 so we get a free mint.

  • The contract uses a modifier isEOA() that checks if msg.sender is an Externally Owned Account and not a smart contract. The modifier uses an opcode extcodesize() that takes in a 20 byte address and returns the byte size of the code. EOAs have empty code regions so the extcodesize() will return 0. However this modifier can easily be bypassed by using a smart contract that has all its logic in the constructor since extcodesize() returns 0 on a contract in construction. Usually if a function uses this kind of modifier there could be a vulnerability there.

IMPORTANT: Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract constructor.

  • FlatLaunchpeg.sol acts as a wrapper for BaseLaunchpegNFT . The contract uses the suspicious modifier isEOA() on an external payable mint function publicSaleMint() which can be exploited with a smart contract.

  • FlatLaunchpeg contract is deployed with collectionSize = 69, maxBatchSize = 5, and maxPerAddressDuringMint = 5. Which means the attack contract must mint 69 NFTs, 5 NFTs at a time.

Attack contract

The attack contract must do the following:

  • Contain all attack logic in the constructor

  • Mint the whole collection of 69 NFTs

    • Must keep on minting while the condition nft.totalSupply() < nft.collectionSize()

    • If the amountToMint + nft.totalSupply() >= nft.collectionSize() it must decrease the amountToMint and then proceed to mint

    • If the two above conditions are satisfied we can call the publicSaleMint(amountToMint)

    • Since publicSaleMint() checks if our address already has 5 NFTs we must immediately transfer them to another address (attacker address) so that we can mint 5 more again

  • Complete contract can be found here


Subscribe to Proxy
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.