Here are my solutions for @filedescriptor’s prompt(1) XSS challenges.
Like Erling Ellingsen’s alert(1) XSS challenges, these challenges are very interesting, and sometimes even frustrating 🙂
(you see can a great write up about that challenge by Alvaro Muñoz here)
The purpose of this post is to explain my solutions for this challenge, and perhaps get feedback for solutions with a smaller payload.
Of course, much of the fun is to solve these challenges by yourself.. so please don’t read before you actually try to solve them alone 🙂
In this post I will cover levels 0 to 8. in the next post I hope cover the rest..
Level 0
no escaping, so the quickest solution i found for all browsers was to use <body onload=”prompt(1)”>
in IE, we can also use the onresize event for <input:
Level 1
Also here, we open a body tag, and exploit the closing > of </article> to close it:
Level 2
Here stuff got a little more complicated 🙂
The escape function seriously disallows equal signs and open parenthesis.
If only the parenthesis sign was disabled, we could have used this nice XSS technique described by Gareth Heyes (http://www.thespanner.co.uk/2012/05/01/xss-technique-without-parentheses/)
<script>onerror=eval;throw’=prompt\x281\x29′;</script>
Unfortunately, also the equals sign for “onerror=eval;” is not allowed, so we need another vector
the solution i found was to inject the xss using a <svg> tag:
here is a great explanation for why it works:
more about svg xss is in mario’s presentation here:
https://www.owasp.org/images/0/03/Mario_Heiderich_OWASP_Sweden_The_image_that_called_me.pdf
Level 3
in this level we need to break html comments, without using anything containing “->”
here again an insight from mario led to the solution:
(I actually found the reference to this tweet in a great post by Jon Passki:
https://communities.coverity.com/blogs/security/2012/11/16/did-i-do-that-html-5-js-escapers-3)
So, the solution looks like this:
Level 4
This is a very nice level.
Basically, the fault of the escape function here, is that it calls decodeURIComponent before checking that the script’s src url matches (https?:)//prompt.ml/
So.. this means that we can enter %2f instead of the trailing / – in order to break the format of a legitimate url.
Now the url is broken, we can convince the browser that the prompt.ml%2f is actually a http basic auth username, that we are passing to a different domain
(i.e. http://user:password@example.com )
If we type //prompt.ml%2f@pmt1.ml it will actually load the content of “pmt1.ml”;
Level 5
here the escape function allows us to pass a quote to the input tag, so we can create new attributes.
it tries to clear all of the onXXXX= events, but it fails because the regex doesn’t handle multi-line input. so we can insert a new line before the equals sign.
now, we could have used the autofocus vector: <input onfocus=”prompt(1)” autofocus>, but also anything containing “focus” is replaced.
The remaining vectors are to use the onresize event for Internet Explorer:
In other browsers, we can override the type of the input to “image” and then use its “onerror” event:
Level 6
In this level, the javascript tries to prevent form submission, if the form’s action contains “javascript”.
the fault here, is that we are allowed to create our own inputs in the form.
so if we create an input named “action”, then checking document.forms[0].action will lead to our new input field instead to the actual form’s action attribute:
Level 7
this is a nice level, where basically we need to build our xss in segments of 12 chars or less
the trick is to use the first segment to close the <p> tag and start our own tag (in my case <body )
then, we open an attribute to contain the “junk” that will be placed between the first and second segments.
in the second segment, we close our “junk” attribute, and open our event (“on load”), then we use a js comment (/*) to contain the “junk” that will be placed between the second and third segments
in the third segment we close the js comment, and call prompt(1)
Level 8
The first challenge here is to break js single line comments.
the escape function does filter out \r and \n, but there are other chars that can break a new line in javascript:
* \u2028 Line Separator
* \u2029 Paragraph Separator
so if we inject \u2028, the output will be:
<script>
// console.log(”
prompt(1)”);
</script>
now the next challenge is to get rid of the trailing “);
it would have been simple if we could use // ot </script>, but / and < are not allowed.
according to http://javascript.spec.whatwg.org/#comment-syntax , we can use –> as a js comment too
so, we go down another line use the closing html comment –>
<script>
// console.log(”
prompt(1)
–>”);
</script>
the easiest way for me to insert \u2028 to the input box was via the console line:
document.getElementById(“input”).value=”\u2028prompt(1)\u2028–>”;
Then, i just put 1 inside prompt():
Hope you had fun reading this post. see you in the next part 🙂
Please share your thoughts comments, and once again, thanks to @filedescriptor on this great challenge 🙂
Really nice. Thank you. Learned a lot from your writeup. Really smart.
Great post and great blog! keep writing!