During our audits, we often encounter user enumerations that could be easily avoided with the right methods. In this article, we will discuss user enumerations on login forms, password reset forms, and account creation forms. However, user enumerations may be present on other features, such as search forms or message submissions.
Description
Definition
A user enumeration allows somebody to find valid user logins on an application. To do this, an attacker will try to enter a number of usernames and observe the behavior of the application, to determine whether an identifier is valid or not (different error messages, different response times and more generally any difference in HTTP responses).
To build an initial list of candidates, an attacker may try to find email addresses or people related to his target on search engines or social networks.
Why this is a problem
This is problematic firstly because if an attacker finds a valid user ID, he can use it to refine his attacks. For example, he could attempt a bruteforce attack on the platform authentication form (if vulnerable to this type of attack), or it could target, for example, identified users with phishing attacks.
Who is affected
It is true that this vulnerability is quite rare at the moment on login forms. However, it remains widespread on password reset forms and even more on account creation forms.
In order to carry out a demonstration, we developed a vulnerable application with PHP, that contains a login form, a password reset form and an account creation form.
Vulnerable login form
As mentioned above, this vulnerability is quite unusual on connection forms, but we sometimes observe it, though.
On the above screenshot, we see that the application tells us that the username does not exist. If we enter a username that exists, the error message is different, as shown below.
We can deduce that the username “admin” exists on the platform. All we have to do now is to find the password.
In order to fix this vulnerability on a login form, you simply need to make sure that the error message returned by the application is the same, whether the password or username are incorrect.
This way, it is no longer possible to enumerate user accounts.
Password reset form
User enumerations are much more present on password reset forms. Indeed, it often happens that the application informs users that the email address or username they entered in the form does not exist on the platform.
If the email address exists, another message is returned, indicating that the password reset link has been sent.
In order to correct this problem, it is possible to always display the same message, whether the user exists or not. For example: “If your account exists, a password reset link will be sent to you in a few moments.”.
The error message returned to the user by the application is now the same, whether the account exists or not.
However, there is often another problem: If the application sends the reset email directly (synchronously) when the user validates the form, a longer latency will be observed if the email address exists (if it does not exist, no email will be sent).
Response time with non-existent account (in seconds):
curl -i -s -k -w %{time_total}\\n -o /dev/null -X $’POST’ -H $’Content-Type: application/x-www-form-urlencoded’ –data-binary $’email=test%40test.com&button=’ $’http://fr.safe. vuln.local/reset.php’
0,005467
Response time with an existing account (in seconds):
curl -i -s -k -w %{time_total}\\n -o /dev/null -X $’POST’ -H $’Content-Type: application/x-www-form-urlencoded’ –data-binary $’email=test%40demo.local&button=’ $’http://fr.vuln.demo.local/reset.php’
0,758968
We notice that the gap here is about 750 milliseconds, which corresponds to the time that the application takes to send the email. This gap is largely sufficient to enumerate functional emails.
To correct that new enumeration, you must be sure that emails are not sent directly when clicking the button but are buffered and sent out by another process that would run for example in a scheduled task, every few minutes. This way it will actually become impossible to enumerate users on this feature.
Account creation form
It is on user account creation forms that enumerations are most common. In the same way as on password recovery forms, it often happens that web applications inform users when an identifier is already taken (here the email address).
If the ID is not already taken, then most of the time the application will display a message that looks like this:
In order not to cause a user enumeration, the solution consists on the one hand to use the email address as an identifier, and on the other hand to always display the same message when the form is validated, even if the email already exists on the application. For example: “Your account has been created, you will receive a confirmation email in a few moments”.
If the email did not exist on the application then the process does not change and we send an email indicating that the account is created and that we must click on a link to validate the account.
If the email already existed in the database, it probably means, in a typical case, that a user who already had an account tried to recreate one with the same email address. In this case, the message to be sent will be, for instance: “You tried to create a user account with this email address but it is already registered on our application. If you have forgotten your password, we invite you to click on the link below to reset it”.
In this way, it will no longer be possible for an attacker to enumerate user accounts, but it will always be possible to inform a legitimate user that he is attempting to use an existing address.
Conclusion
It is obvious that the biggest difficulty lies more in the ergonomic choices (user journey, messages), which are not exclusively under the responsibility of the developers.
Even if user enumerations are not as serious as other vulnerabilities such as SQL injections or XSS, they remain a great deal of information for potential attackers and their impact is too often underestimated by developers. Since the corrections to be implemented are not really complex, we strongly encourage them to be applied, as far as possible.
Author: Romain GARCIA