Vimeo account takeover

A while back I was playing around with the OAuth2 spec and discovered a flaw in how Vimeo associates Facebook accounts. Their Facebook connect callback URL was vulnerable to a Cross Site Request Forgery, allowing an attacker to connect their Facebook account with a victim's Vimeo account.

Background

If you try to connect a Facebook account to your Vimeo account, Vimeo sends you to the following URL:

https://www.facebook.com/v2.1/dialog/oauth?client_id=19884028963&redirect_uri=https%3A%2F%2Fvimeo.com%2Fsettings%2Fapps%3Faction%3Dconnect%26service%3Dfacebook&scope=email,public_profile,publish_actions,user_friends&state=f599e2d1b07d64214116415646a6a653  

Once you accept the authorization prompt, Facebook returns an HTTP 302, redirecting you back to Vimeo's redirect_uri along with a code that Vimeo uses to access your Facebook info and associate the accounts.

Along with the code, Facebook sends back the state value from the URL above so that Vimeo can verify that the callback request is authentic and originated from the same browser that started the flow.

Vimeo correctly set a state parameter, but used code similar to the following to verify the state:

def callback  
  if params[:state] == session[:state]
    # associate accounts
  else
    # error csrf detected!
  end
end  

But what is session[:state] when the request is not authentic?

Attack Scenario

1) The attacker logs into their own Vimeo account and beings the flow to connect their Facebook account.

2) The attacker accepts all permissions, but uses a tool like NoRedirect to block their browser from making the final redirect back to Vimeo:

https://vimeo.com/settings/apps?action=connect&service=facebook&code=<CODE>&state=<state>#_=_  

3) The attacker uses this URL, omitting the state parameter as part of a CSRF attack on a page that the victim (who is currently logged into Vimeo) is likely to view.

<img src='https://vimeo.com/settings/apps?action=connect&service=facebook&code=<CODE>#_=_' />  

4) The victim's Vimeo account is now associated with the attacker's Facebook account. The attacker can now use their Facebook to login to the victim's Vimeo account.

Remediation

The callback must ensure that the state query parameter matches the persisted state token AND that both values are non-nil.

Timeline

  • 04 Feb 2015 - Reported the vulnerability to Vimeo
  • 25 Feb 2015 - Vimeo marked the report as a 'duplicate'
  • 25 Feb 2015 - Vimeo requests verification on the 'duplicate' report
  • 26 Feb 2015 - Verified that Vimeo's fix corrected this issue, but the 'duplicate' bug remained vulnerable
  • 06 Mar 2015 - The 'duplicate' report was independently disclosed publicly by Egor Homakov.
  • 02 Apr 2015 - No updates from Vimeo on the 'duplicate' issue or acknowledgment that two reports were separate vulnerabilities