Exploit a Smart Contract⚓︎
Direct link: Bored Sporc Rowboat Society website
Exploit flaws in a smart contract to buy yourself a Bored Sporc NFT. Find hints for this objective hidden throughout the tunnels.
Psst. Hey, slick - over here. Myeah.
You look like a sucker ahem I mean, savvy..
I got some exclusive, very rare, very valuable NFTs for sale..
But I run a KringleCoin-only business. Kapeesh?.
Ever buy somethin' with cryptocurrency before?.
Didn't think so, but if you wheel and deal with ya' pal Luigi here, now you can!.
But we're currently in pre-sale, and you gotta be on the list. Myeah, see?.
BSRS NFTs are a swell investment. They'll be worth a pretty penny, and that's a promise..
So when they're purchasable, you better snatch 'em up before the other boneheads ahem I mean, eggheads do..
I got a business to run. You can't buy nothin' right now, so scram. Kapeesh?
Merkle Tree Arboriculture
Plant a Merkle Tree
You can change something that you shouldn't be allowed to change. This repo might help!
Finding the application flaw⚓︎
Merkle trees, how do they work?
The second and third bullet points in the instructions on the BSRS presale page state that very high-techy-techy Merkle trees are being used to validate if someone's wallet address is on the approved list to buy a Bored Sporc NFT. To help understand what they are and how they can be applied to the use case of an NFT pre-order approval list, we can use Professor Qwerty Petabyte's excellent explanation of the concept.
In short, storing information in the blockchain is expensive. To work around this, Merkle tree root and leaf node values are calculated from the list of approved wallet addresses and only the root value is stored in the blockchain. Users on the approved list are then provided with a series of leaf node values called a proof which can be used in combination with the user's wallet address to calculate the root value. If the calculated root value matches the original value stored in the blockchain, the user is confirmed to be on the approved list.
The NFT presale is backed by the
BSRS_nft.sol smart contract which we can find in block #2 on the blockchain. When we submit the form on the BSRS presale page, the leaf node value of our wallet address and proof are used as parameters for the smart contract's
verify function. The function takes these values, calculates the Merkle tree root value, and then compares it to the root value which is also provided as a function parameter. All is well until we look at the client-side code though. The
do_presale function in the
In other words, the
verify function in the
Validating the vulnerability⚓︎
Using Professor Petabyte's Python script we can generate the smallest possible Merkle tree based on just two wallet addresses, our own personal wallet address and a randomly chosen value. As a result, the Merkle tree will only contain two leaf nodes and a root node. Start by cloning the repository using
git clone https://github.com/QPetabyte/Merkle_Trees.git and replace the first item in the
allowlist variable on line 149 with the wallet address we want to appear as being on the approved list.
Next, run the script using
python merkle_tree.py which will generate the Merkle tree values shown below.
We can now validate the generated root (R) and proof (N2) by using our web browser's developer tools to first update the
root variable in the
do_presale function and then submitting our wallet hash (1) and generated proof (N2) via the HTML form on the BSRS presale page. Alternatively, we can use a tool like curl to manually submit the POST request to
/cgi-bin/presale. As we're just testing, make sure to keep the Validate Only option checked or the
Validate field set to true in the HTTP request.
Looks like we successfully tricked the website into thinking we are on the allowed list. It's time to go shopping!
Running the exploit⚓︎
Just like when we purchased our hat, we first need to use a KTM to approve a payment of 100 KC to the BSRS wallet address at
0xe8fC6f6a76BE243122E3d01A1c544F87f1264d3a. Next, we head back to the BSRS presale page and repeat the steps from the validation phase by first changing the
root variable in the
merkle_tree.py script (i.e.,
Finally, we enter our wallet address and the
0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a proof value generated by Professor Petabyte's
merkle_tree.py script, uncheck the Validate Only option, and submit the form!
The success message confirms we are now the proud and official owner of a Bored Sporc NFT!
|BSRS Token #000013|
1 2 3 4 5 6 7
Blockchain transactions - Blocks #23207, #23219, and #23220
Block #23207 - Payment approval⚓︎
First, the details of the payment approval are stored in block #23207. This block holds the transaction from our personal wallet address to the
KringleCoin.sol smart contract address where the
approve function is called with the BSRS wallet address and 100 KringleCoin as input parameters. Go on, take our money!
Block #23219 - Transfer funds⚓︎
Next, block #23219 shows the transaction from the BSRS wallet address to the
KringleCoin.sol smart contract address where the
transferFrom function is called to transfer the approved 100 KringleCoin from our wallet to the BSRS wallet. If the exploit fails, we're out 100 KC and have nothing to show for it!
Block #23220 - Verification and NFT minting⚓︎
Last but not least, the NFT minting transaction is stored in block #23220. This block contains the transaction from the BSRS wallet address to the
BSRS_nft.sol smart contract address where the
presale_mint function is called with our wallet address, the generated proof, and the generated root as input parameters. The
presale_mint function in turn calls the
verify function to confirm our wallet address and proof add up to the root value we also submitted. The proof and root values are stored in the blockchain as bytes. We can convert them back to hex and confirm they are indeed the values we submitted.
|Convert bytes to hex using Python|
1 2 3 4
Buy a Bored Sporc NFT by exploiting a flaw in the smart contract.
What!? How'd you get on the list? What's that? You's a double agent, and you're actually workin' for us?
I don't know if I buy that, but you're on the list, so... myeah.
Somethin' about this ain't sittin' right with me, but there's no reversing transactions with cryptocurrency.
That NFT is yours to keep, but if I find out you're lyin' to me, Palzari's gonna pay you a visit. Kapeesh?
How was a plebeian such as yourself granted access to the pre-sale?
I present thee with a proffer to purchase the NFT you've acquired for twice the price.
Hwhat? You shan't vend to me? Have you any idea who I am?
You just refused the abhorrent Count Chorizo!
I shall ensure you are nevah able to transact with that NFT agayn!
Hmph... this is so boring...
"This is a serious task" he said, "not a sporc headbutting-party" he said.
"Mess this up, Slicmer, and I'll tie a rock to your feet and throw you down a well!" he said.
I think this job was just to keep me out of his way. Luigi thinks I'm a blockhead.
Well I think he's a -- Huh? Wait a minute...
Hey! Boss! I think I see somethin'!
Tsk tsk tsk, I thought I told you to play nice?
The only reason you're not in time-out is because Luigi doesn't seem convinced that you're a little rascal.
He's not as clever as he likes to think. But once he comes around...
You better watch out, dear. And when I catch you, you better not cry. Or do, not even Santa will hear you.