How it started.
In October of last year, I had the pleasure of collaborating with a close friend to search for vulnerabilities in an NFT bug bounty program. Drawing from our diverse skill sets and expertise, my friend, who has extensive knowledge in blockchain-related technologies, and I, with a background in web applications, formed a highly effective team that operated seamlessly, leading to one of the biggest bounties of our career.
Our Hunting Methodology.
In order to ensure a comprehensive and well-informed approach, we meticulously delved into the documentation available to us, taking care to read it in its entirety, in order to gain a deeper understanding of the target. Throughout this process, we happened upon the NFT metadata documentation, where one field in particular, the animation_url, piqued our curiosity and warranted further investigation. By thoroughly examining this aspect, we were able to uncover potential vulnerabilities that could have otherwise gone unnoticed.
As the animated NFT feature was unavailable on the Web UI, my friend created the animated NFT in the testnet blockchain with an HTML file pointing to one of my domains.
After implementing it, the animated NFT in the website was referenced as the following:
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" frameborder="0" height="100%" sandbox="allow-scripts" src="https://evilsite.com/yourfile.html" width="100%" style="min-height: 500px;"></iframe>
We got an iframe, but with the top window referencing nftsite.com and I just controlling a child iframe, what could we do? That’s where your hacker mindset should pop.
Playing Around with the possibilities.
We then discovered that we could use the sandbox=”allow-scripts” feature to load our Chrome wallet extensions, such as Metamask and Coinbase, which worked as expected.
Then my head was like:
“what if I can interact with the victim’s wallet, or even better, try to steal their NFTs or takeover the account?”.
For example, sending the following postMessage will result in a prompt window asking you to sign an Ethereum Message.
Having invested a few minutes in the rigorous investigation and after several unsuccessful trials on Metamask. I arrived at a stunning revelation in Coinbase Wallet: the postMessage dispatched from the child iframe would readily display the domain of the top window. As a consequence, in the event that you chanced upon my evil NFT on that marketplace, I could quickly induce you into performing actions on your wallet, all under the guise of a legitimate signature request from the NFT platform, displaying the logo and domain of the legit NFT site.
- postMessage sent from the top window will show the top domain in CoinBase wallet (eg nftmarketplace.com).
- postMessage sent from child window/iframe (evil.com) will show in the wallet prompt the top domain (nftmarketplace.com). Hijacking the top domain.
We got the jackpot!
Demonstrating Impact, centralized GraphQL API in a decentralized world.
We then discovered that the NFT site had a centralized GraphQL API to manage collections, profile pictures, etc. The login system worked by sending the connected wallet from the browser to the GraphQL server, which replied with the message to be signed. The sign postMessage prompt was sent, and once the message’s signature was received, it was sent back to the GraphQL API. A valid JWT token was generated to modify the profile and do everything to the user’s account.
Our exploit involved creating a PHP script that grabbed the wallet address from the browser and sent it to our server. We asked GraphQL to give us a message to be signed and sent it back to the victim. When the victim signed it, they returned it to us, allowing us to generate a valid JWT Authentication Bearer token and take over the account with one click (sign message when visiting our NFT).
To be more clear, we graph it:
In result, our exploit managed to Hack a visitor to our NFT that clicked into a sign message that was exact the same as the legit login flow.
- October 6th 2022: the site has been notified.
- October 12th 2022: the report was triaged.
- October 19th 2022: a $XXX,XXX bounty was awarded.
- December 2022: Coinbase and multiple other affected wallets fixed all features that made able this chain to work. No interaction from child wallets are possible under sandbox, and the top domain display issue has been fixed.