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.

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.

A nice cheatsheet about 2FA

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).

OTP key and QR code hidden in the DOM despite 2FA being already enabled.

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.

First thing I had to do was to disable OTP, then ask a for a new key and submit it along with a valid OTP code to enable 2FA back again. The hardest past is to generate an OTP from Javascript.

For this, is used this great JS-OTP library.

And below is a proof-of-concept of JavaScript code to do that.

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.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store