Tags:


MetaMask JavaScript Security Stack (Part 2 - Snow) [๐•]

Originally posted on X

In Last week's tweet (โ†“) we discussed "scuttling", a LavaMoat ๐ŸŒ‹ feature we enable on MetaMask ๐ŸฆŠ for enhanced supply chain security.

However, near the end I hinted scuttling isn't so simple in reality..

Browser JS security folks? Come learn why, and how Snow โ„๏ธ saves the day:
It's the same scuttling demo from last tweet, but with an addition demonstrating a security flaw with scuttling that leverages non-configurable property "document" to bypass the scuttling feature
First, it's important to clarify there are multiple groups of properties we don't/can't scuttle, each group for its own reasons (scuttling is hard to achieve!)

Today I'll focus on the "non-configurable window object properties" group.

But first - how does scuttling even work?
For starters, we need to understand what to scuttle.

To do that, we'll collect all the properties that are accessible via the window.

That must include own properties of the window itself, but also own properties of every one of the prototypes in its prototype chain: Collecting all the properties one can access via the global object window (taken from LavaMoat source code)
Once we have that list, it's time to scuttle!

Pretty simple, we just iterate the props we collected, and redefine their getters to deny access to their real values, and instead return "undefined" (for the sake of the example).

But as you can see, the scuttling attempt fails... It's a scuttling attempt that fails after trying to redefine a property that is not allowed to be redefined
In JS (by legacy), some props of the window object are non-configurable by definition (we're not gonna get into why).

This means that some properties aren't going to cave in under scuttling - ever.

Question is - which ones? And how useful are they going to be for attackers?
These are the 8 props that are non-configurable in the browser, and cannot be redefined whatsoever.

* Infinity, NaN, undefined - are primitive values and therefore are not very powerful for attackers ๐Ÿ‘
* window, top - refer back to the window object, which we already scuttle ๐Ÿ‘ Finding and listing all the properties that belong to the window itself that are not allowed to be redefined by default in the browser
* chrome - very powerful for attackers (will elaborate on another thread one day)

Luckily, even though is not configurable, it is writable, meaning we can't redefine its getter, but we can redefine its value to be undefined ๐Ÿ‘

Which leaves us with only two: document & location. The only 2 out of the 8 non configurable props that are actually putting scuttling in danger
And unfortunately, if code escapes LavaMoat sandbox and gets access to either one - it can be pretty bad.

Today, we'll focus on document access, why it's dangerous, and how we use our very own Snow JS โ„๏ธ to reduce that risk.

document access is dangerous for obvious reasons:
DOM access allows attackers to intercept the interaction users have with the app. They can change its layout deceitfully, thus tricking the user to take actions that might compromise its account or its private key.

That's bad, but mitigating that isn't our top priority, because: (poorly) demonstrating how attackers can change the layout to trick users into sharing sensitive info with the attackers without intending to
1. Fully sandboxing the DOM was proven before as practically impossible.

Projects have tried achieving {parts of} that before (e.g. CaJa) and have learned how tangled up the DOM really is.

It'll take some time before we decide to retake on that challenge.

But most importantly:
2. We're less worried of DOM interception, as it ultimately requires UI (=user interaction) to compromise MetaMask.

We're far more worried about powerful JS capabilities the window object grants, with which attackers can breach MetaMask without any UI - which is why we scuttle!
So... what's so bad about it?

If that's the "obvious" and "less prioritized" reason we're worried about DOM access - what's the less obvious, more dangerous reason?

Short answer? iframes.

Long(er) answer?

iframes introduce new realms, which in the browser translate to... Escaping the sandbox and accessing the window object won't grant attackers access to APIs such as "fetch" or "alert" thanks to scuttling, but with "document" still being accessible, attackers can create a new iframe and just reach in to its own "fetch" and "alert" APIs, thus bypassing the concept of scuttling
... New windows! Meaning, more windows to scuttle! ๐Ÿ˜ฑ

So in reality, assuming attackers escaped LavaMoat sandbox, bypassing scuttling is simple - just create a new iframe and steal the scuttled props from its window!

And what's the single prop needed to create a new iframe? ๐Ÿ‘‡ Demonstrate how alert fails thanks to scuttling, but then calling an alert of an iframe instead bypasses scuttling successfully.
Does that make scuttling useless? KINDA.

Does that make my last tweet a lie? Am I just a big phoney?

Well, not quite. By integrating scuttling with Snow โ„๏ธ, we're eliminating the threat, but in a different, also advanced way.

Getting 2 long though, so wait for nxt week's ๐Ÿงต ๐Ÿ˜‰
There it is, part 3