POSTS
Real-life OIDC Security (II): Login Confusion
This is the second post of a series on Single Sign-On and OpenID Connect 1.0 security. In this post, the novel Login Confusion attack is described in detail. We use Bitbucket Server as an example.
The series consists of following posts:
- [Overview] Common Issue Patterns and Derived Security Considerations
- [Implementation] Login Confusion
- [Implementation] Injection of CRLF sequences
- [Implementation] SSRF issues in real-life OIDC implementations
- [Specification] Redirect URI Schemes
- [Specification] Reusable State parameter
- [Responsible Disclosure] Lessons learned during Responsible Disclosure of OIDC/OAuth related issues
As you can see, the series is structured in an [Overview], attacks with concrete examples categorized as [Implementation] flaws and [Specification] flaws, and finally lessons learned during the [Responsible Disclosure].
Note that this post gives detailed insights into the Login Confusion attack.
Acknowledgment
We made the observations within this advisory during the research for my master’s thesis on “Single Sign-On Security: Security Analysis of real-life OpenID Connect Implementations”. The thesis was written at the chair for network and data security of Ruhr University Bochum.
The advisors of my thesis are Dr.-Ing. Christian Mainka (@CheariX), Dr.-Ing. Vladislav Mladenov (@v_mladenov) and Prof. Dr. Jörg Schwenk (@JoergSchwenk). Huge “Thank you” for your continuous support! 🙂
Introduction
The following post requires basic knowledge about OpenID Connect 1.0 (OIDC) and OAuth 2.0.
In general, three parties interact during an authentication process using OIDC:
- The Service Provider (SP) that wants to provide a service to End-Users.
- The OpenID Provider or Identity Provider (IdP) that authenticates the End-User for the Service Provider.
- The End-User that authenticates to the Service Provider using an existing account at the Identity Provider.
Service Providers often support multiple authentication mechanisms, for example, using “native” accounts that have dedicated credentials and are managed by the SP or alternatively using “SSO” accounts that are registered at an Identity Provider (e.g., Google, Twitter, Github, …).
Prerequisites
- The Service Provider needs to be vulnerable to Login Cross-Site-Request-Forgery (CSRF), i.e., there is an endpoint that launches an OpenID Connect (OIDC) flow with a pre-configured Identity Provider. There are two common cases regarding OpenID Connect 1.0 implementations that fulfill this prerequisite:
- Login Initiation Endpoint: The specification [2] defines a third-party Login Initiation Endpoint that serves as an intentional CSRF protection bypass as pointed out by Fett et al. in [1].
- Non-normative External Login Endpoint: Some Service Providers implement internal endpoints that are used to start an OIDC login flow.
We present a generic Login CSRF flow in the following:
- The Service Provider needs to implement a non-normative parameter that holds the redirection target after a successful login (commonly named nextUrl, url, next_url, …). Additionally, session relevant relative paths like the Login Initiation Endpoints can be specified as destination after login.
- The victim has two accounts at the Service Provider: One “native” account to which she authenticates using credentials (denoted as user A in the following) and one “SSO” account which is linked to an account on an external Identity Provider (denoted as user B in the following). Furthermore, the victim has an active session at the Identity Provider.
Attack Flow
A generic Login Confusion flow is presented in the following:
If the previously outlined prerequisites are met, the following steps can be performed:
- The victim requests the Login UI: https://sp.com/?next=/oauth/start. As one can observe, the
next
parameter holds the relative path of the Login Initiation Endpoint. - The victim authenticates through the Login UI with credentials for user A.
- After successful authentication, the victim is redirected to the
next
URL (Login Initiation Endpoint): https://sp.com/oauth/start. - Without further interaction, the Login Initiation Endpoint starts a new OpenID Connect flow with the pre-configured Identity Provider including a valid
state
that is issued by the Service Provider. - Since the victim has an active session for user B on the Identity Provider, it immediately redirects the victim to the
redirect_uri
. This redirect includs thecode
and thestate
. - The Service Provider completes the OpenID Connect flow by redeeming the
code
at the Token Endpoint. As it receives anid_token
for user B from the Identity Provider, user B is logged in at the Service Provider. As a result, the victim is now authenticated as user B, even though she entered her credentials for user A and did not perform any additional user interactions.
Example: Bitbucket Server
Bitbucket Server is a self-hosted Git management software: https://www.atlassian.com/software/bitbucket
Setup and Prerequisites
For our test environment, we use the official Docker image available at https://hub.docker.com/r/atlassian/bitbucket-server/. Additionally, we need to set up our instance with a “Data Center” license, as the required “SSO 2.0” configuration would not be available in case we use a “Server” license. Finally, we require that the Bitbucket instance has a (secondary) OpenID Connect Identity Provider configured (Bitbucket can be configured to either only support authentication using OIDC or using OIDC as secondary authenticator with credentials as primary alternative method).
For our victim, we require that the victim browses an attacker-controlled website. Prerequisites for this attack are that the victim has two accounts at Bitbucket. For user A our victim uses credentials. User B is authenticated using an external Login Provider. Additionally, the victim has an active session at the Identity Provider.
Steps to Reproduce
Bitbucket implements two endpoints that enable intentional login CSRF. Both endpoints do not implement CSRF mitigations so that with a request to https://bitbucket.test/plugins/servlet/oidc/initiate-login or https://bitbucket.test/plugins/servlet/external-login an OpenID Connect login flow is started. If a user has an active session at the Identity Provider and previously gave consent to share information with Bitbucket as Service Provider, the Identity Provider immediately responds with the Authentication Response when the Authentication Endpoint is queried.
Furthermore, both endpoints allow GET parameters that specify where the user should be redirected to after successful authentication. While this parameter is sanitized to prevent Covert Redirects to external destinations, any path of the Bitbucket instance is allowed as a final destination, including session-related endpoints like the Logout Endpoint (that terminates the user’s session) or the Single Sign-On Login Initiation Endpoint. This sanitization enables the following Login Confusion attack:
Prerequisite (recall): The victim has an active session at the Identity Provider and previously used this account to authenticate as user B at Bitbucket.
- The victim visits an attacker-controlled website and is redirected to https://bitbucket.test/login?next=/plugins/servlet/external-login.
- Bitbucket serves a regular Login Form, the victim authenticates using her credentials for user A (1).
- After successful authentication, Bitbucket redirects the victim to the Login Initialization Endpoint, as this was the previously provided destination (2).
- Bitbucket receives the GET request to the Login Initiation Endpoint and launches a new OpenID Connect Login flow accordingly.
- The victim has, per our prerequisites, an active session at the Identity Provider. As a result, there is a silent redirect with the Authentication Response to the
redirect_uri
endpoint including validcode
andstate
parameters. - Bitbucket validates the
state
and redeems thecode
at the Identity Provider’s Token Endpoint. The Identity Provider responds with anid_token
andaccess_token
. - After validating the identity of user B, the victim is logged in as user B, although she entered her credentials for user A and did not perform any additional interactions.
To conclude the previous steps: The victim authenticates using credentials for user A but is then logged in as user B after multiple intransparent redirects and without further user interaction. This underlines the conclusion Fett et al. [1, Section III;A. 7)] drew in 2017: Endpoints that provide OpenID Connect related functionality require Cross-Site-Request-Forgery protection.
Demo
The following video demonstrates the Login Confusion issue present in Bitbucket. Note that in the above video the native account is userB and the SSO account is userA.
Impact
The above-described behavior has a direct effect on the End-User’s session, does not require any privileges, and leads to an unforeseen login status from the End-User’s perspective. If an End-User does not observe that the finally authenticated account is not the intended account, the End-User may perform actions with the wrong account that could, for example, leak their SSO Identity to third parties.
The impact is limited by the fact, that both accounts are under the control of the victim. The attacker cannot log in a victim into an attacker-controlled account, unless the Identity Provider has further flaws.
Recommendation
The Login Initiation Endpoint and External Login Endpoints should be removed entirely to mitigate this behavior. Alternatively, token- or referrer-based CSRF mitigations should be implemented. Furthermore, endpoints that have effects on the session should be entirely excluded from target_link_uri
and next
parameters, as a silent request to these endpoints has unforeseen effects on the current user session and the application’s behavior.
Responsible Disclosure
Atlassian’s triage process on Bugcrowd is very transparent. Their Security Team outlined that the above-described behavior is “intended behavior”. The report’s status was changed to “won’t fix” accordingly.
During direct communication with Atlassian’s security team using mail, they allowed using Bitbucket as an example in this blog post.
- 2020-06-08: Submission of the described behavior as “follow-up” to initially rejected report via https://bugcrowd.com/atlassian.
- 2020-08-18: Atlassian’s Security Team informs us that they reviewed the follow-up but still consider the report as “not applicable” regarding their policy:
I’m still not able to find the vulnerable component in the workflow. The scenario you described can happen with any IdP, this is not specific to bitbucket.
- 2020-09-21: Security team agrees on publishing this blog post:
Yes, please feel free to discuss those findings in your blog post. As you mentioned (and as was discussed in those submissions), we’ve determined each of those issues fall outside of our security model for Bitbucket Data Center and therefore will not be addressed.
Note that not every Service Provider is vulnerable to Login Confusion and that the countermeasures are quite trivial to implement, as presented within this post.
References
[1] https://dl.acm.org/doi/10.1145/2976749.2978385
[2] https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin
Thank you for reading this post! Stay tuned for the following posts of this series, as they will include more examples and detailed explanations of vulnerabilities that were found within popular real-life OpenID Connect Implementations.
If you have any feedback, feel free to reach out via Mastodon, Twitter or LinkedIn. 👨💻
You can directly tweet about this post using this link. 🤓
Special thanks to Dr.-Ing. Christian Mainka (@CheariX), Dr.-Ing. Vladislav Mladenov (@v_mladenov) and Louis Jannett (@iphoneintosh) for your feedback on this post prior to publication! 🙂