DOM XSS – auth.uber.com
So, after reading a lot of write ups about bug bounty its finally time to write one of my own.
I hope that you will be able to take something from this into your bug bounty journey.
I don’t do much bug bounty, but I love to read write ups about bugs that have been found by other bug bounty hunters as I think it’s one of the best ways to learn new techniques.
This write up will be about a DOM XSS I found in auth.uber.com domain.
It all started with this link:
Probably most of uber users are familiar with this one, but if you don’t here is the deal:
When an unauthenticated user tries to visit an uber domain such as m.uber.com, riders.uber.com and more, those domains will redirect him to the login screen at auth.uber.com and will include a parameter named next_url which is responsible for redirecting the user back to the original domain after successful login.
If an authenticated user accesses this link, he will be immediately redirected to the url found in the next_url parameter with a 302 response.
What is the first vulnerability that comes to mind when you see such behavior?
You guessed right (or not), It’s an open redirect.
So, I decided to try it out by changing the domain in next_url parameter like this:
Apparently there is some whitelist check on the server side of the application that allows redirecting only to valid uber sub domains (but not all of them) such as m.uber.com or accounts.uber.com.
I tried to bypass this validation using different open redirect bypasses but nothing seemed to work.
Here is a good tutorial by @zseano which summerizes some of the techniques:
During my tries to bypass the domain check I noticed something, there was no validation performed on the scheme of the next_url parameter.
Now I was able to send something like this:
The location header:
But it will not work as the majority of browsers will not support this behavior any more.
Now my goal was to find a scheme which will perform a redirect and will bypass the domain validation. After some manual fuzzing I was able to come with this bypass using DATA protocol:
which will lead to the following response:
Some of you probably think why didn’t I just poped the alert box and submitted an XSS to uber.
Also it is important to mention that that redirect technique will only work in firefox browser and not in chrome.
Chrome will block this request for two reasons:
- Chrome is not supporting redirect to data scheme using Location header
- Chrome parses pages differently from firefox and will not tolerate syntax errors in the data protocol (data:accounts.uber.com;html/text – remember?)
Error message when redirecting to data protocol using location header:
Copy pasting to the url bar:
So here is the first lesson to take from this write up: Different browsers behave differently in some situations, so if your payload is not working in one of them this is not an indication that others will not execute it.
At this point after achieving open redirect, which is not in scope of the uber program, I left this attack vector and went to do other stuff.
Few weeks went by and I was bored again so decided to take another look at this.
Then I logged in to my uber account using my link I noticed something that I missed before, the redirect process is different when you try to access the URL with no active session.
After you complete the login process the server response looks like this:
How could have I missed this behavior?! Well probably because I did most of the work in repeater with an active session, which always reaulted in a 302 redirect response.
So, do you see it?
Usually it means something like this:
window.location.href = nextURL;
In theory if I am controlling the nextURL parameter (which I am), I can perform XSS by using this method:
window.location.href = data:accounts.uber.com;text/html; HTML_CODE
So I tried to login using the following link:
AND STIL NOTHING…
But this time is see the data in the browser URL bar which means I got redirected for sure. But where is the alert box?!
First I needed to confirm that the origin of this page is auth.uber.com:
F12 (Developer tools) -> console tab -> alert(document.domain);
And I got this alert box:
Quick view source on the page and everything looks fine…
Why there is no alert box?!
After checking my request history I noticed this:
Content Security Policy… Is this what stopping me? But where is the header? It is not in this response:
After quick search in burp history:
I performed a quick test, to confirm that this is the reason the alert box not popping, by removing the CSP header from the response, then I accessed the following link:
BOOM ALERT BOX!
So now I have a confession to make, I never had the need to bypass CSP before so I am not so familiar with it I just heard about this in some bug bounty write ups.
I started by reading the documentation about this protection and some write ups about how to bypass it.
Here some links I used:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP ß documentation
So after some time spent on this here are the conclusions:
The part that is important to us:
- I can’t use inline script because there is a random nonce value (changes every request), so no: <script>alert(1);<script>
But what are the chances to find something like this you ask? Well apparently pretty high.
After few minutes of googling I found this:
The final link:
Quickly assembled the new payload and I got this:
Logging in and….
But It was only working when the user is not logged in, how can I increase the impact?
As it turns out, if you remove the state parameter from the URL, uber forces the user to login again so the final link looks like this:
Anyone who will press this link in firefox will be redirected to a login page, which will lead to XSS.
So things to take from this write up:
- Always try your payloads in multiple browsers.
- Always try to notice all the path of application behavior.
- Read bug bounty write ups they are a great source of information.
- And never give up ;)