How To Make a Password Cracker
Practical Bruteforce Attacks in Web Applications and Web Services
The reason WarGames is still relevant although it was released in cinemas in 1983 is not because of the movie plot but mostly because the tools and techniques to hack into remote computer systems have not dramatically changed in the past 30 years. Simply put, in many cases what separates administrators from normal users is nothing more but the knowledge of a password. It does not sound glamorous and indeed it is as noisy as it gets but in the majority of the cases bruteforce attacks are the most practical and easy way to break into systems by taking advantage of bad password management practices.
Web Applications and Web Services are particularly vulnerable to password bruteforce attacks. This type of software is relatively easy to access, it is abundant, it is available remotely by default and most of all it is custom and subject to constant change to keep up with the latest developments in Web technologies. In this post, we will cover a number of different types of web application bruteforce attacks from a practical perspective. We will also use off-the-shelf free web security tools like AppBandit Attack Proxy or Fuzzer from the Online Suite to demonstrate each attack in depth.
Since the early days of the World Wide Web, Basic Authentication and some of its variations, such as Digest Authentication, NTLM and so on, is the defacto standard for authentication. It is no secret that Basic Authentication is sufficiently insecure to be used for any practical purposes but this does not stop developers utilising this authentication scheme to password-protect router management interfaces, web services, administrative interfaces and much more. One of the reasons why it is so wide-spread is because Basic Authentication is relatively straightforward to implement as the whole authentication scheme relays on a specially constructed header, which contains both the username and the password encoded in base64 format.
Let's set up a brutforce attack against a basic authentication prompt. We need to open AppBandit's Fuzzer or the Fuzzer from the online suite and configure a few parameters. First of all, we need to set the Authorization header and then we need to add the Basic Authentication item, which was purposefully build for this specific task.
For the username, we will use a list of known accounts. We can also use a common dictionary from some well-known databases. We will get on to this in a second but we will keep this part simple.
For the password, we will use an actual dictionary. AppBandit nor Fuzzer come with their own dictionaries. Instead, both tools can download and include dictionary files provided from the community. Add a dictionary item from the drop-down and simply search for "password" and you will find the list of various collections from many kinds of most common password lists and actual password list extracted from well-known past data breaches.
Ensure that you increase the maximum parallel requests to 60 or more and reduce the timeout to something like 5 seconds in order to increase the performance of the attack. Sure enough, soon on later we find the right password by simply monitoring the response codes as illustrated by the screenshot below.
Many applications, particularly mobile apps, utilise what is known as PIN-based authentication, i.e. authenticating with 4 to 6 digit code. Two-factor authentication based on token-generation sent over email or SMS also falls under this category because it is often incorrectly implemented. Needless to say, PINs provide low entropy to be considered secure. Bruteforcing pins, whether you decide to bruteforce them sequentially or at random is straightforward.
Let's set up the attack against a fictitious JSON service. Configure the request so that it is considered valid by the service. In the body, we will use a chain of items to correctly encode the generator for the pin. First, we need JSON encoder to quote the value. We also need a Format item to pad the value to the correct pin length. This is useful for the next step.
The pad item contains a simple counter, i.e. for loop. The counter goes from 0 to 9999 with step 1. The reason we use the pad is that only 4 digit numbers are considered valid pins. We need to add extra zeros in front of the number to cover all pins starting with zero to make a four-digit pin. We can use the same technique for 6 and 8 digit pins as well.
Setup the attack options as desired - i.e. increased number of concurrent request and reduced timeout. Execute the attack. Unlike the Basic Authentication bruteforce example, we saw earlier, which provides a straightforward mechanism based on status code to differentiate valid from invalid attempts, this type of attack entirely depends on the application so you need to come up with your own heuristics. For example, you may want to monitor for content-length changes or changes in the status code, i.e. 302 redirects could mean successful authentication. It is also possible to sort the responses based on how much time it took to come back - i.e. a timing heuristics. It is really up-to-you but it is the same principle at the end of the day.
This same attack can be configured for form-based authentication and even Basic Authentication. You just need to move the generator to the desired place. The rest will work exactly the same.
Needless to say, form-based authentication is the most common type of authentication scheme on the web. Practically any PHP application implements one - most of the time badly. If correctly implemented the form-based authentication should be resilient to automated password guessing attempts but although it may sound simple, this is by no means easy in real-world scenarios as there are many corner cases that require specific type of handling.
To set up a form-based authentication bruteforce attack we need to follow the same steps with the Basic Authentication example. This time we will not use the Authorization header but we will have to follow set up the parameters that are expected by the application. We can capture that information first by the AppBandit Proxy or tools such as HTTPView which work straight from your own browser without additional setup.
We can get pretty clever as especially if the username is an email and we want to cover more ground. For example, instead of bruteforcing one account with many passwords, we could bruteforce a small subset of common passwords against many accounts and we can also dynamically generate the accounts as we will do next.
So let's set up a generator for our user list. First, we will define some variables to make the attack a lot more configurable.
As you can see, we are using some dictionaries (most of them from seclists). We dynamically generate the email address. In practice, we can cover more than one domain in the same attack.
Now let's add the top 100 more common passwords from the same list. We use another dictionary from seclists as shown in the example. As you can see, we can get pretty creative with this.
Once the attack is running you need to keep an eye on the running task for clues that will indicate a valid login attempt. For the majority of the responses, we will get the same result. Those requests which contain valid credentials will differentiate in a number of ways as we discussed earlier. You need to come up with your own heuristics. Most of these scenarios are covered by the built-in filters. For example, you can filter responses that contain valid cookies. In most cases, this is an indication that the authentication was successful.
Web authentication systems are funny in a sense that they can never be perfect. If they are too secure then they will be inaccessible. If they are too accessible they are they are most likely insecure. As a result, of this, there are a number of things to keep in mind when cracking passwords with any of the techniques covered above.
Account lockout is a common defence mechanism against brute-force attacks but it can be converted to denial of service depending on the situation. For example, imagine that the username is guessable or sequential and account lockout is set in place. Since we can generate valid usernames with high degree of success this means that we can also lock everyone out of the system - i.e. denial of service. While this is not an achievement to be proud of in any security assessment, it is also nevertheless a valid finding.
Converting between horizontal and vertical bruteforce attacks is also a common technique. In other words, instead of testing many passwords against a single account, we can test for one password against many accounts given that we can either enumerate the accounts or generate them somehow with high degree of success.
Some authentication systems naively lock out valid authentication attempts if they come from the same IP address. Later, these systems are refactored to have a number of exceptions because it is discovered that IPv4 address space is relatively small and many customers are likely going to have the same IP - for example, many mobile and fibre networks actually work like this. An attacker might be able to utilise one of these networks or trick the application to believe they originate from networks in the exception list to bypass the account lockout restrictions.
Similarly, if the authentication system blocks IPs or NETBLOCKs based on the attacker's IP address, a bruteforce attack can be converted into denial of service as the users in the same network will not be able to log in. Again, this is particularly important for mobile networks as it is unlikely for the mobile user to have a dedicated public IP address. As such mobile applications are particularly affected.
Finally, just because there is reCAPTCHA on the page it does not mean it is used. Many times it is there for show. Often reCAPTCHA, or any other CAPTCHA system, is embedded but not checked against due to misconfiguration or code change which was the result of a change. These types of regressions happen often.
Deauthentication may not actually work - i.e. although it will appear that the user is logged off, the actual session is not destroyed. Previously used sessions can be reused by the attacker. This topic requires a separate section on its own as it is pretty vast. The point is that sometimes it is possible to login without knowing the passwords. There are other ways.
Some Final Words
There are many ways an attacker can pull a successful password cracking / bruteforce attack and as mentioned earlier it is pretty common. We are yet to see a security system being implemented to completely eradicate these type of attacks. Frankly speaking, it is impossible as long as we rely on passwords. There is no doubt that two-factor authentication schemes are significantly more secure but we also need to acknowledge that they are often optional and in some cases, they can be bypassed.
In the followup article, we will discuss some of the defence mechanisms currently available.