# Mr Steal Yo Crypto - Jpeg Sniper

By [Proxy](https://paragraph.com/@proxy-3) · 2024-01-20

---

### 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](https://github.com/KirinFilip/mr-steal-yo-crypto-ctf-foundry/blob/implement/test/AttackContracts/1-JpegAttack.sol)
    

### Links

*   [Challenge link](https://mrstealyocrypto.xyz/jpeg-sniper/index.html)
    
*   [Github contracts](https://github.com/0xToshii/mr-steal-yo-crypto-ctf/tree/implement/contracts/jpeg-sniper)
    
*   [Attack contract](https://github.com/Proxy1967/mr-steal-yo-crypto-ctf-foundry/blob/implement/test/AttackContracts/1-JpegAttack.sol)
    
*   [EXTCODESIZE Checks](https://consensys.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/extcodesize-checks/)
    

* * *

---

*Originally published on [Proxy](https://paragraph.com/@proxy-3/mr-steal-yo-crypto-jpeg-sniper)*
