Dangerous 2FA implementation on TrixCMS.eu
Today I would like to continue my previous post on TrixCMS.eu stored XSS, specifically its 2FA implementation. Some parts of this post also applies to the CMS itself.
TrixCMS.eu XSS stocké via upload SVG
Ce matin, je découvre l’existence d’un CMS axé multigaming nommé TrixCMS. Ayant déjà trouvé de multiples vulnérabilités…
XSS is a strong on its own, but can be extremely powerful when combined with CSRF exploits (which you hardly really prevent once XSS is acquired). TrixCMS.eu and the CMS were quite nice targets to study how 2FA should not be implemented on a website.
By chance, there is apparently no 2FA bypass on TrixCMS.eu or the CMS. There are many examples of 2FA bypasses on the web but it usually implies sending an other account’s OTP or simply removing 2FA parameters from the request.
Fun with 2FA
1. Disabling 2FA
When disabling 2FA, you should be asked for an OTP. Otherwise, a CSRF might disable your 2FA security without you knowing. That is the case of TrixCMS.eu and a request to
/profile/twofa/disable/ with an appropriate CSRF token will simply remove the security from your account. Same applies to the CMS.
2. Stealing the OTP key
The OTP key was simply stored in the DOM (this is now fixed).
3. The OTP key does not change between 2FA toggles
On TrixCMS.eu, the OTP key is only generated once when you first enable 2FA. If you disable then re-enable it, you are prompted an OTP code with the same key. If your key is somehow leaked, you cannot change it.
On the CMS, you actually regenerate the key by requesting
/users/profile/load/2fa/ every time you enable 2FA. Which leads me to…
4. Locking the account by recreating a fresh OTP key
Disabling it and submitting a valid OTP code based on a newly generated OTP key. Since you do not need the OTP to disable 2FA, you don’t even need to steal the key first. This was actually a fun little exploit to develop.
For this, is used this great JS-OTP library.
This demonstrates how an attacker would silently steal 2FA credentials with or without locking the account. Moreover, in a scenario where the user tries to recover his password by email, he would not be able to log in anyway as the OTP key should never be removed without authenticated interaction.
This must obviously be combined with a way to retrieve the user’s password in order to reach the 2FA login page, but this is another topic.