[Bypass for CVE-2023-1965] SAML RelayState parameter still allows for arbitrary redirection
HackerOne report #1972880 by joaxcar
on 2023-05-04, assigned to H1 Triage
:
Report | Attachments | How To Reproduce
Report
Summary
GitLab version 15.11.1 contained a fix for CVE-2023-1965 titled Account takeover through open redirect for Group SAML accounts
". The issue was that GitLab allowed any URL in the RelayState parameter to propagate through the application after a SAML authentication and then redirect the user to this URL.
In the fix this code was added
def saml_redirect_path
return params['RelayState'] if params['RelayState'].to_s.start_with?("/")
begin
parsed_uri = URI.parse(params['RelayState'].to_s)
rescue URI::InvalidURIError
parsed_uri = nil
end
if parsed_uri.present? &&
(parsed_uri.scheme =~ /\Ahttps?\z/i) &&
(parsed_uri.host == Gitlab.config.gitlab.host) &&
(parsed_uri.port == Gitlab.config.gitlab.port)
params['RelayState']
else
group_path([@]unauthenticated_group)
end
end
Where we can see that unless the RelayState parameter starts with a slash (a relative path) it will be returned as is. If not it will go through this check to see that it is pointing to the configured gitlab origin. The URL is later used by redirect_to
to redirect.
The problem here is that an URL can start with double slash //
and will then in a lot of cases (for example by redirect_to
) count as a new URL (reusing the current scheme) and not a relative URL. So given the RelayState of //evil.com
the fix will be bypassed and the redirect will again end up outside of Gitlab.
CVSS
The original researcher was able to show an impact of account takeover through this by leaking tokens after the redirect. There is nothing in the fix that prevents that from happening with this bypass, thus I will keep the CVSS at the same level. I have not managed to recreate it myself, but the Gitlab team will have access to the other report and will be able to confirm this.
Steps to reproduce
SAML
First, you need to register a SAML provider. I have tested this with Auth0 and Okta and they both work. Auth0 is a bit easier to set up. Follow this guide here to use Auth0 for SAML
https://auth0.com/docs/authenticate/protocols/saml/saml-sso-integrations/configure-auth0-saml-identity-provider#manually-configure-sso-integrations
The only addition to this guide is that you need to add this config during the step of setting up the SAML web app addon
{
"nameIdentifierFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
}
When configuring the SAML service you need an "Application callback URL" this one will look like this https://gitlab.com/groups/testagain2/-/saml/callback
with your group name
In Gitlab
- Create a new group (Ultimate license)
- Go to https://gitlab.com/groups/testgroup/-/saml
- Activate SAML and enter the IDP and Fingerprint given to you by Auth0
- Now visit the link under "GitLab single sign-on URL" it will look like this https://gitlab.com/groups/testgroup/-/saml/sso?token=TOKEN
- Make sure to log all requests, either in the network tab or in Burp
- Click "Sign in"
- First there will be a POST request to Gitlab, then there will be a redirect to Auth0 with an URL containing a SAML request and a RelayState
- Copy this URL and open it in a new tab instead. Replace RelayState value with
//example.com
- Log in to Auth0 in the prompt.
- You will be redirected to GitLab and then directly redirected to example.com
Easy way out
Use my test Auth0 for an easier time
IDP: https://joaxcar.eu.auth0.com/samlp/iUZCIvymBh4JCXyuJDUQ4ydcFRpPJCWb
Fingerprint: 43:9F:EF:A3:A2:7C:C9:FC:28:09:CC:FA:2E:0C:57:E5:55:8B:D7:E5
And login with the user
Username: testuser@joaxcar.com
Password: TestUserPassword.
(note the dot in the password)
Impact
Bypass of CVE-2023-1965 leading to open redirect capable of account takeover
What is the current bug behavior?
RelayState is not checked for //
URLs
What is the expected correct behavior?
Check for double slashes in the URL, or validate it in opposite order
Relevant logs and/or screenshots
In this screenshot here you can see that the GitLab endpoint gets a RelayState sent to it containing //example.com
and that the next request is for example.com
Output of checks
This bug happens on GitLab.com
Impact
Bypass of CVE-2023-1965 leading to open redirect capable of account takeover
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section:
Implementation approach
Based on the previous fix Account takeover through open redirect for Grou... (#406235 - closed) we'd need to add an allow-list of URLs that are accepted as RelayState parameters to avoid this problem