It was the year 1964 when a young economist, Stefan Mandel, won 72,783 leu from a Romanian state lottery. There are many similar stores where a really lucky player got a once in a lifetime win only to be never heard from again. Except, Stefan went on to win a total of 14 lotteries in his lifetime including the $27 million Virginia state lottery in 1992. He did it by finding weaknesses in lotteries around the world which allowed him to all but guarantee a win. Modern lotteries have instituted new rules and increased the number of combinations to stop the likes of Stefan Mandel. However, the brave new world of DeFi introduced new opportunities for enterprising folks to try and successfully beat the odds again.
In this blog post, I will dive into one such DeFi lottery heist where a player won a very rare and valuable Meebit NFT which they sold for 200 ETH (~$700,000 at the time). You will learn technical details about the hack, explore the attack timeline, and learn how to replicate it in yourself.
It all started on May 3, 2021 when Larva Labs announced their latest NFT project called Meebits, a collection of 3D avatars designed for virtual worlds and games. In order to reward their early investors, Larva Labs allowed anyone holding their other NFT projects, Cryptopunk or Autoglyph, to redeem them for a single free Meebit. The process was called a “community grant” which was open for only 7 days.
Below is the code snippet from the Meebit smart contract which implements the giveaway logic:
The mintWithPunkOrGlyph function above takes a Cryptopunk or an Autoglyph ID and returns a newly minted Meebit. Only 20,000 Meebits can ever be minted each with different attributes of varying rarity. Below is a sample transaction log which illustrates a single Meebit #4563 getting minted using Cryptopunk #3341:
You can check what kind of Meebit was minted in the above transaction by quering the contract using Etherscan to obtain the ERC721 metadata link:
Below is the contents of the above URL including the corresponding Meebit’s type. “Human” is fairly common and less valuable than others:
Since NFT ids are sequential, it was possible to brute-force all possible token URLs in order to identify rare types such as “Dissected” or “Visitor”. However, the smart contract itself made it even easier by including an odd variable contentHash in its source code:
The above hash corresponds to a file which can be downloaded from any IPFS gateway. The file included a complete collection of ERC721 metadata files for each of the Meebits. This data can be quickly parsed to identify IDs of ultra-rare “Dissected” and “Visitor” types:
It took only a few days for the twitter user 0xNietzsche to figure out a way to exploit this. He waited until Saturday, May 8th 10:19 AM UTC to initiate the attack after playing with a few test contracts on the mainnet. The following Ethereum addresses were involved in the attack:
- Attacker #1: 0xb08be767cdc33913f8e2fa44193f4e2eb5725876 (0xb08b)
- Attacker #1: 0x009988ff77eeaa00051238ee32c48f10a174933e (0x0099)
- Attacker #2: 0x6887444a5b74b746f56ae08952f4e1b404ff7ca5 (0x6887)
The first two addresses are associated with the Attacker #1 (0xNietzsche) who found the weakness and deployed the exploit contract used in the attack:
- Exploit Contract: 0x270ff2308a29099744230de56e7b41c8ced46ffb
Attacker #2 appears to be a unique actor who attempted to aid Attacker #1’s exploitation efforts without the ability to actually profit from it.
Below is a timeline of the attack (all times in UTC, addresses abbreviated):
Before initiating the brute-force attack, Attacker #1 purchased Cryptopunk #4466 which was not yet used to claim a free Meebit. Next, the attacker deployed the exploit smart contract which would attempt to generate new Meebits and revert if it’s not on a specially selected list. This allowed him to continue generating new Meebits with a single Cryptopunk while only paying for gas fees.
On 2021/05/08 11:11:13 AM UTC, after only one hour of brute-forcing Meebits, Attacker #1 successfully received a rare Meebit #16647:
Following the successful mint, Attacker #1 sold the newly minted Meebit for 200 ETH and proceeded to purchases Cryptopunks #5039, #3334, #6353, #7242, #4335.
At 11:49:46 AM UTC Attacker #1 began another brute-forcing session using Cryptopunk #5039 in an attempt to mint more rare Meebits. Attacker #2 joins the brute-forcing session at 12:27:40 PM UTC; however, Larva Labs paused the market 4 minutes later preventing further exploitation.
Overall the attack was fairly successful where the Attacker #1 profited 200 ETH while only spending about 5 ETH in gas, 1 ETH in miner bribes, and 0.036 ETH in contract deployment fees.
As we have seen above, the attacker deployed the exploit smart contract at 0x270ff2308a29099744230de56e7b41c8ced46ffb in order to perform the brute-force attack. Contract source code was not available, but I was able to reconstruct the source code using the excellent Panoramix decompiler:
The most important function above is the mintMeebit (not the original name) which was used by Attacker #1 to mint the rare Meebit #16647. Notice the require statement on line 39 which reverts if an undesirable Meebit was minted. It allowed an Attacker #1 to call mintMeebit again and again with the same Cryptopunk until hitting jackpot. Another interesting element in the mintMeebit function is on line 42 where the contract transfers 1 ETH to a miner to ensure that this transaction will be included in a block.
You can experiment with the above contract by downloading a PoC exploit to run the exploit in a local environment as follows:
It took more than 1000 attempts to mint a rare Meebit #12304 on my local machine using Brownie and Ganache; however, none of the 20,000 Meebits were yet claimed. After 5 days of the community grant program with many of the Meebits already claimed, it took only 100 attempts for the Attacker #1 to mint Meebit #16647. That said, it was definitely a race against the clock before Larvalabs would detect brute-force attempts and pause the market. It was a gamble, but it paid off!
Attacks targeting NFTs are still very rare. However, as their value continues to increase, more malicious actors will likely take interest in this new asset class.
On the positive LarvaLabs’ response was quick even on an early Saturday morning in the US. It took about 2 hours between the attacker initiating the exploit and LarvaLabs pausing all minting.
On the improvement side, NFT issuers can learn from several errors made by LarvaLabs which led to the exploit:
- LarvaLabs failed to consider a scenario where a smart contract could attempt to cheat by brute-forcing randomly generated mints.
- LarvaLabs exposed all of the token NFT attributes in the IPFS hash hard-coded in the contract itself which exposed all of the rare token ids.
- LarvaLabs prematurely exposed all of ERC721 JSON files on their website which allowed anyone to enumerate rare token types.
Just like lotteries exploited by the infamous Stefan Mandel in the late 20th century, NFT and other digital asset issuers will learn their lessons and harden their systems. While the morality of the exploit is questionable, the real victims are honest Cryptopunk and Autoglyph owners who were cheated out of a fair competition to earn a rare Meebit. It’s unfortunate, but that’s another day in the new frontier of blockchain security.
If you enjoyed reading this analysis and are interested in the field of blockchain security, check out my Blockchain Threat Intelligence newsletter where I cover news about many other incidents involving smart contracts, exchanges, blockchains, crypto malware, and others. To learn more about smart contract security be sure to visit the OpenBlockSec project for curated lists on CTFs, incidents, talks, and other educational materials.