Closed magicmac closed 1 year ago
Hi @magicmac! BIG FAN HERE!
I Read many of your stuff over the years at https://www.brokenbrowser.com/ - I'm honored you dedicated time to breaking Snow!
This vulnerability is super interesting actually, because it demonstrates an inherent problem with Snow as a solution. This proves how 2 realms (one cross origin and one same origin) can help bypassing Snow in so many ways, so easily (🥲).
frames
array.This goes not only for data:
iframes, but for any cross origin iframes an attacker can control.
In other words, the attacker can also redirect their realm to //malicious.com
which will load <script>document.write('<iframe src="${top.location.href}"></iframe>')</script>
, and then once again access it from top and abuse it.
So the problem here is more around how do we protect against cross origin realms forming inside them same origin realms to be later abused?
My intuition is to enhance Snow's capabilities from just same origin realms, to also local cross origin realms. Because even though data:
counts as cross origin, if it loads fully locally, Snow can hook into that as well.
So by protecting that vector, and also integrating frame-src
CSP directive to defend against remote cross origin realms, Snow might still be able to complete its mission after all.
This will require:
data:
but maybe more?).This requires some thought, feedback is highly appreciated!
Thanks again @magicmac! What are your thoughts on this?
Yeah, I agree with all of what you are saying, Gal. I thought about the intermediary malicious.com website but data: looked more elegant and didn't need an external resource :)
Anyway, Gal, fantastic work! I will keep coming from time to time to play with it. =)
data:
, so if I could somehow hook into creation of such realms, I can edit the URL to include a Snow protection (e.g. data:text/html,<script>alert.call(top)</script>
-> data:text/html,<script>HOOK_SNOW_FIRST()</script><script>alert.call(top)</script>
). That way this realm will also be protected by Snow and therefore its potential children as well.window['top']
/ window[0]
/ etc are configurable:false by default)Just tinkered with https://lavamoat.github.io/snow/demo/#self-xss-challenge-msg and figured a straight forward datauri seems to be enough. It doesn't even require an additional iframe.
const content = `alert(123)`
const prefix = `data:text/html;charset=utf-8,`
const iframe = document.createElement('iframe')
iframe.src = `${prefix}<script>${content}</script>`
document.body.append(iframe)
I wonder, also for blob urls, would it be possible to either rewrite the url as you mention here https://github.com/LavaMoat/snow/issues/73#issuecomment-1465685301 or in the case of a blob url maybe you could just fetch the content of that blob url when the iframe enters the document and replace the blob url with a new blob url which uses the same content but adds the snow shim?
Yes, but data:
is a cross origin to the top main realm we protect, and therefore is by definition out of Snow's scope 😊 (see old https://github.com/LavaMoat/snow/issues/7#issuecomment-1216339426 by @benjamingr).
As for the 2nd part, blobs have made life so complicated for Snow. Luckily, we landed some powerful protections for blobs, but their so messy that I wouldn't be surprised if are not bulletproof. Furthermore, protecting blobs required some rare scenarios in Snow where the protecting patch we apply not only applies Snow protection, but also alters/blocks natural browser behaviour (not proud of it, but must be done for some edge cases).
It's complicated with blobs because being a local resource, loading an HTML blob inside an iframe will execute the HTML before calling the iframe's event listener, which leaves Snow 2nd to run. This is frustrating because you can't reproduce this behaviour with iframes otherwise (except for about:blank
, but about:blank
doesn't load any arbitrary HTML to begin with).
There are so many PRs and issues about blobs in Snow that I can't really share all of them without making your head spin.
It's complicated with blobs because being a local resource, loading an HTML blob inside an iframe will execute the HTML before calling the iframe's event listener
Yeah, you would presumably want to patch the .src
setter on iframes to intercept it before and if it's a data url (base64 encoded or otherwise) add snow to that realm.
Though as you mention you said it's out of scope.
Patching .src
was declined after considering it seriously. The conclusion is that defending attributes modification in really hard, and most likely doesn't worth the effort and should be approached differently if possible.
We will try to inject ourselves into data:b64
frames because of the vector presented by @magicmac, we'll see where that takes us.
Next step would be to address #122, so that it's clear for the users what they need to do to protect themselves fully against #73
This issue has (hopefully) come to an end thanks to #122 🎉
This is a very tricky exploit that Snow might not have much it can do about. Therefore it was decided that it would be best if Snow integration will include calling Snow in every HTML file served by the same origin.
Intuitively you might think "if so, no need for Snow then" - Well, you'd be surprised, there are many other types of same origin attacks regardless of this.
Thank you for this wonderful discovery @magicmac ❤️
Hey Gal! Nice to "meet you". I was reading your DevTools detection mechanism yesterday and I ended up landing into this LavaMoat. The challenge looked interesting (you know, when it bites you, you can't stop!) so I give it a few tries, and luckily, it worked!
Here's the code. I believe the best strategy to patch this would be to check whenever a non-accessible domain has iFrames inside, and if that's the case you can continue iterating and testing until you make sure none has access.
Have a great day!