Many online services use SMS as a user authentication mechanism. But small mistakes are made that will lead to big problems. This is what this article will be about.
Introduction
This authentication method is popular in b2c services, because it increases conversion, because the user does not need to remember passwords, come up with logins, but simply enter his phone number, which will receive an SMS code for confirmation.
At the same time, some typical threats to account security are excluded, such as simple passwords, password database leaks, and simple phishing.
Threats
Based on the experience of participating in penetration testing projects, as well as in bug bounty programs, we have identified a number of main threats that can be implemented in relation to the SMS authentication mechanism.
Account Takeover
This most critical threat consists in hijacking an arbitrary user’s account, for example, when knowing his phone number.
Registration as another user
The impersonation threat is not so critical, but the damage depends on the specifics of the service. As a rule, if impersonation is possible, hijacking of an already registered account is also possible, since the confirmation mechanism is the same.
SMS flooding of any phone numbers
An SMS flood can be directed both to system users and to any subscribers, while the actual mechanism of authentication of the vulnerable web service is used to send messages. For the web service itself, flooding is fraught with loss of customer loyalty and reputational damage.
Depletion of web server resources and balance on SMS gateway
To send messages, web services connect to various providers providing SMS messaging services, each of which is charged. Thus, in the course of an SMS flood, both the pool of resources of the server itself (network channel, memory, queue, disk space) and simply the account balance in the SMS gateway can be depleted.
Vulnerabilities and attacks
Examples of vulnerabilities of all the described classes were discovered by us in the framework of security analysis projects, as well as in the framework of bug bounty programs.
No Rate Limit
This is the most common class of SMS authentication vulnerabilities, and the exploitation of such a flaw is obvious: the confirmation code can simply be iterated over, since there are not enough restrictions on the number of attempts.
As a rule, the confirmation code consists of 4-6 digits, so the maximum number of requests required to brute force is 1 million, which is not a lot for the modern web.
Binding Rate Limit to Cookie
Sometimes the number of login attempts is tied to a cookie, and an attacker may simply not send the corresponding cookie so that login attempts are not counted.
Same code for different actions
The vulnerability lies in the fact that the code sent to confirm an action in one interface (for example, on the registration page) can also be used for another interface (for example, to enter an account).
An example of such a vulnerability from bug bounty: when logging into an account, an SMS code was received, and it was impossible to iterate over it, because the number of attempts for authorization was limited, however, if you send the same code to the API for registration, then when you send the correct code, the application returns following answer:
1 | {“message”:”Пользователь с таким номером телефона уже зарегистрирован”,”type”:”already_registered”},”field_errors”:null} |
At the same time, there were no restrictions in the registration interface, which means that it was possible to capture any account by selecting the registration code and sending it as a confirmation code for entering.
Lack of code lifetime
It happens that there are no restrictions on the number of attempts, but the code has a short lifespan, and it is difficult to pick it up.
As part of bug bounty, a vulnerability was discovered in such a mechanism in one of the popular services: despite the fact that the lifetime of a 6-digit code was only 3 minutes (and it is rather difficult to send 1 million requests in 3 minutes), in reality there was no lifetime generally, because when the code was re-submitted, the application was sending the same code.
Apparently, the programmers felt that there was no need to generate a random code again if no one had read or entered the previous code. Thus, for a full iteration of 1 million options, it was enough to request a re-sending of the code (and receive new cookies) approximately every 2.5-3 minutes.
SMS flood
The rate limit should limit not only the number of attempts to enter with one number, but also requests to the application in general, since an attacker may try to flood not to a specific user, but massively, in order to damage the service itself.
Unsafe random numbers
As you know, the confirmation code must be random, therefore, if it can be predicted (for example, if its value depends only on the current second in Unix time), any account can be hijacked.
We also met with the fact that the vulnerability was caused not by randomness of the confirmation code itself, but by its identifier. In one of the services, each confirmation code was assigned a number, which, as it turned out, was a global identifier and was incremented for each next code issued to a user.
When the user entered the code, the following object was sent to the server:
1 | {“code”:”1111″,”verification_code_id”:6717620}} |
It turned out that the number is not tied to a session, so an attacker can send incorrect confirmation codes on behalf of other users who are trying to log in or register at that moment. Knowing the current value of the verification_code_id, you can flood confirmation requests by adding various numbers to the current value, thereby causing a denial of service.
Blocking users
The previous vulnerability and related attack is a special case of a DoS attack.
If, when the rate limit is exceeded, the application provides for blocking the user’s account, a massive denial of service is possible: the attacker can simply make several unsuccessful attempts to enter the code for each of the clients, thus blocking all accounts. Of course, for this you need to know their phone numbers or logins.
Interception of SMS
It is no secret that SMS is an unsafe transport for data transmission. There are a large number of ways to intercept messages, including attacks at the level of the SS7 signaling network, attacks on a subscriber via GSM, compromising an SMS provider’s gateway, compromising a client’s personal account on the operator’s website, etc.
The ability to intercept SMS using the methods described is usually not a drawback of the implementation of the web service itself, but the risk of such an attack must be taken into account when developing an application.
Recommendations
To reduce the level of risk, we urge you to follow the following tips:
- Use 6-digit verification codes
- Limit the number and frequency of attempts to enter a confirmation code from one IP address
- Consider the number of attempts both in the current session and in total for the phone number
- Do not block user account after several unsuccessful attempts
- For each login attempt, generate a new unique code
- Use a separate code to confirm each action
- Don’t use predictable IDs and verification codes
- For especially critical services, do not use SMS confirmations, replace with 2FA or at least push notifications or calls