Hacking EthGlobal: Strength in numbers to RCE

Elyx0
4 min readSep 18, 2021

--

We entered the hackathon as sponsors but I decided to give it a shot as well.

Earlier in March, EthGlobal had a weekend NFT hackathon. Participants had a few days to spin up a proof of concept and we would be part of the sponsors as Charged Particles giving support in Discord to people building on our NFT protocol.

Now let’s take a look at their website.

EthGlobal website main component is the global chat, alongside a live video of the event where users can discuss twitch style.

I quickly dumped the html+css with Charles Proxy and went ahead to look at how the user data is treated along the way.

filter.js is actually just a replace profanities into ****

The only interesting piece to work with resided in chat.js (Link) as the sources are not minified we notice a lot of template management for building the HTML looking “hand crafted” which is generally a good lead.

Failures and injections from templating functions are not unheard of, even for our dear underscore.js

Secondly we notice a lot of calls to Firebase Firestore which I was familiar with.

Turns out the website allows you to register an account to be able to chat:

Time to input weird stuff here

After some quick recon to figure out where there fields are served back to us in the HTML code, namely the user name, prepending chat lines:

Which translates into the following html:

Would be a shame if that <b class=”c-name”> part of the template was not rock solid

Most of the template data to be inserted looked like it was protected thanks to DomPurify which is supposed to be an XSS fortress.

it would be a shame if we did some other data manipulation on perfectly safe fields

Fair enough c-name looks strong here and sliced to 50chars, outch. We take a mental note that it’s added then to window.messages that is then sorted by time. This window.messages is actually a custom List() implement by https://listjs.com/ 1.5.0

The problem arises with the updateMessages() function. It is called from this part of chat.js which triggers at page load:

Basically this returns the list of recent users as a JSON then calls updateMessages for each document

What does updateMessages do?

updateMessages overrides the previous sanity checks for the c-name field, outch again.

.values() is actually a DOM modifier according to https://listjs.com/docs/item-api/ so we have potential injection.

After a lot of experimenting with what’s allowed or not, we use the registration POST URL to register our malicious user (MU) with a name of:

<img src onerror=console.log(1)/>

And then while logged as MU, we post a message in the chat so it triggers updateMessages ..for everyone live on the page, and sure enough if you were to open your console at home on EthGlobal while I was hacking it in the background, you would have seen…

Great we have injection! But that’s already 33/50 chars just for a console log. Oof.
This is how Chrome renders it HTML-wise

The problem is now, anything we enter in the name that’s > 50 chars gets rejected by the backend server. Firestore simply returns blank for our user name payload.

Thankfully we’ve full of experience since https://elyx0.medium.com/xss-dangers-stealing-top-players-accounts-fad1f52b7a66 and we know there is strength in numbers.

So what do you do when you can only input 50 chars into a payload per user… well… you build your new payload bit by bit using multiple users with each name a bit of the payload, so their chat messages payloads chunks will trigger the final payload.

Thanks to the page having jQuery provided we win a lot of chars

dd.ngrok.io would then load my custom payload, as lengthy as I’d like.

I meant the background of the Enter button.

And what they saw doing so:

It was easier to see how this could escalate in an abuse of MM or embedding web3.js ourselves into the page and prompt the UI for “Special NFT Hack giveaway, 1ETH to enter, no loss lottery 🎉” or some kind of setApprovalForAll and steal all their ETH & NFTs at a later date.

Metamask would like access to steal all your funds. Aka something like the Banksy hack.

You could also try to get the team IPs so the MM never gets prompted for them while you run the attack… but that’s beyond the scope of this article.

Anticlimactically I was rewarded with… nothing besides the sanitizing function now being at my name… so much for white hacking nowadays.

The ethglobal easter egg no one would ever know about so I had to write this article.

ETHGlobal is currently running #ETHOnline, good luck to all!

--

--

Elyx0
Elyx0

Written by Elyx0

Gone rogue Dailymotion Engineer

No responses yet