Hello,
I work as a pentester and regularly encounter Keycloak deployments at our customers, where TOTP codes are used as a second authentication factor. What I'm noticing that we keep finding MFA bypass vulnerabilities at those customers, caused by the lack of brute-force restrictions on TOTP codes.
Since TOTPs are only six-digits long the chance of a random code matching whatever TOTP is valid at any given time is only 1 in a million. When the default "look around window" of 1 is used (and 3 in a million when the case when the default "look around window" of 1 is configured). In practice, this meant we could successfully bypass MFA within a few hours per account in each case where we had this finding.
This is not a new observation. We found this advisory from 2021 about this insecure-by-default configuration:
https://herolab.usd.de/en/security-advisories/usd-2021-0016/. The recommendation was to enable Keycloak's brute force protection mechanism, which applies to both password and OTP-based logins. There are a few issues with this approach, however:
- Ideally, we'd like to recommend enforcing a permanent lock-out after a large amount of invalid OTP's are entered. After all, at the point an attacker can submit these they have already compromised a user password. However, because the same policy applies to the password-based login as well this creates a Denial of Service vulnerability in which an unprivileged external attacker can lock out user accounts by simply submitting a number of invalid passwords.
- It does not appear to be clearly documented that the same brute force protection mechanism applies to both passwords and OTPs.
- End users expect that when they enable two-factor authentication, that a quite trivial bypass of that authentication factor is possible. In one case a customer originally made the decision not to use brute-force protection for passwords, because the presence of MFA made them accept the risk of password guessing.
- When using TOTP, many administrators falsely assume that this is impractical because codes change every minute, not realizing that doesn't in the case of a probabilistic attack.
- It is quite difficult to design a lockout policy that effectively mitigates this risk. For example: one customer had a policy of locking an account for 15 minutes after 15 invalid attempts. This would allow an attacker to perform an average of one OTP guess per minute; meaning it would take around 230 days to do 333.333 attempts. This may seem reasonable, but only applies when the attack targets a single user. If an attacker knows more than one user password, they can run multiple guessing attacks in parallel; effectively multiplying their request rate by the number of users whose password was compromised. If 10 passwords are known, for example, the expected guessing time needed to find an OTP of one of those users becomes less than a month with this policy. This scenario is not unreasonable for large organizations, as we often find dozens of valid passwords when carrying out password spraying or credential stuffing attacks against them.
My proposed solution for these issues would be separate brute-force protection measures used for passwords, from those used for OTPs. The OTP policy may be configurable, or even just hard-code a single reasonable policy. My recommendation for a default setting would be to enforce a permanent lockout when more than X invalid OTPs are submitted in a row. If X is somewhat high (say, 100) it is unlikely that a legitimate user who has issues with their authenticator app will manually enter that many codes before giving up. But X=100 would make malicious guessing attacks completely unfeasible, even when multiple user passwords are breached at once.
Now, I am not a Keycloak administrator myself, and please let me know if I am missing any new features or changes that already address this issue. But I was not able to find documentation on those.
Of course there may be other effective approaches to address the issues I mentioned as well. But I do think the current situation does pose a significant risk to Keycloak users. While it (T)OTP brute-force attacks (unlike some other types of MFA bypass techniques) are still relatively obscure and not widely exploited "in the wild" as far as I know, this could change at any point.
Sorry for the lengthy message. I hope this mailing list is an appropriate channel to raise issues such as these.
Best regards,
Tom Tervoort