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:
First behavior:
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.

Second behavior:
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:

ANNNDDDDDDDD NOTHING….

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:

Now the first thing that comes to mind is to use the javascript scheme, which will lead to 301 redirect with the following location header: 


The location header:
Location: jaVAscript://accounts.uber.com/%0a%0dalert(1)//

But it will not work as the majority of browsers will not support this behavior any more.
*also notice that I wrote jaVAscript and not javascript(lowercase), this is because the second option was blacklisted on the server.

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:

 Encoded:

Decoded:

which will lead to the following response: 

As you can see I was able to get the redirect using javascript code(window.location) by utilizing the data protocol.

Some of you probably think why didn’t I just poped the alert box and submitted an XSS to uber.
Well this is because the javascript code is not running in the origin of the auth.uber.com domain. Then the redirect performed using 301 response with location header, the origin of page is changing so in this case the origin is null.



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?
There is no redirect using location header and the response code is 200 but I still got redirected, which can mean only one thing, the redirect is performed using javascript in the borwser.

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 = jaVAscript://accounts.uber.com//%0d%0aalert(1);//

or this:

window.location.href = data:accounts.uber.com;text/html; HTML_CODE

So I tried to login using the following link:


ANNNNNNNNNNNNDDDD nothing…

Probably because there are some client side checks than prevent the use of javascript scheme. I decided not to waste time on this and try the other method:


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:

So after some time spent on this here are the conclusions:
The part that is important to us:


  1.  I can’t use inline script because there is a random nonce value (changes every request), so no: <script>alert(1);<script> 
  2. My only chance is to find a domain which is approved by the CSP and will be able to return my input as javascript.

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:

PERFECT!

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:
  1. Always try your payloads in multiple browsers.
  2. Always try to notice all the path of application behavior.
  3. Read bug bounty write ups they are a great source of information.
  4. And never give up ;) 


Comments

  1. A great write up. I was so inclined to know what you did next. Very informative and entertaining. Thanks.

    ReplyDelete
  2. great one. it helps people like me(beginners)

    ReplyDelete
  3. Fantastic and thanks for inspiring us further through thos great blog !!

    ReplyDelete
  4. Awesome :-)
    Thanks for sharing. Its worth to read.

    ReplyDelete
  5. This is an awesome writeup, congratulations :D

    ReplyDelete
  6. This comment has been removed by a blog administrator.

    ReplyDelete
  7. This comment has been removed by a blog administrator.

    ReplyDelete

Post a Comment