How to brute force online login credentials with Hydra

Photo by olieman.eth on Unsplash

How to brute force online login credentials with Hydra

Hyrda is a beloved tool for penetration testers to brute-force online passwords. Hydra is featured filled, open-source and supports any protocol you could think of. You can see all the protocols supported by Hydra on their GitHub under the INTRODUCTION header.

Hydra has a graphical user interface with the xhyrdra package but I am only covering the command line use of hydra in this article.

Bruteforcing logins

This is the general syntax for brute-forcing logins.

hydra -l user -P passlist.txt -t 4
hydra -l user -P passlist.txt -t 4 ftp <-- you can change this out
-lThe username
-PList of passwords
-tThe number of threads used
-VOutputs every attempted password

Bruteforcing forms

Using hydra on web forms is slightly harder. First off, you need to know whether the form you are submitting is using the GET or POST methods. The easiest way is to press ctrl+u to see the page source or use the network tab in the developer settings. You also need to know what the names of the headers are for the data you are submitting. Generally, they will be "username" and "password" but it is good to double-check. An example of what a form looks like is below:

from view-source:

  <body class="text-center">
    <form class="form-signin" action="/login" method="post">
      <a href='/'><img class="mb-4" style='width: 200px;' src="/img/herc.gif" alt=""></a>
      <h1 class="h3 mb-3 font-weight-normal">Login</h1>

      <label for="inputEmail" class="sr-only">Username</label>
      <input type="text" name="username" class="form-control" placeholder="Username" required autofocus>
      <label for="inputPassword" class="sr-only">Password</label>
      <input type="password" name="password" class="form-control" placeholder="Password" required>
      <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
      <p class="mt-5 mb-3 text-muted">&copy; HydraSite 2012 - 2020</p>

You can see that this form is using the post method and is using the headers username & password. In addition, we need to know the subpage on the form where the login page is. In this case, it is "\login". We then can use the structure below.

hydra -l <username> -P <wordlist> IP http-post-form "/login:username=^USER^&password=^PASS^:F=incorrect"
-lSingle username
-PIndicates the use of apassword list
http-post-formindicates the type of form
/login urlthe login page URL
:usernamethe Form field where the username is entered
^USER^tells Hydra to use the username
passwordthe Form field where the password is entered
^PASS^tells Hydra to use the password list supplied earlier
Loginindicates to Hydra the Login Failed message
F=incorrectIf this word appears on the page, its incorrect and continue brute-forcing

Using Proxies

The easiest way to use proxies is to set the HYDRA_PROXY variable. You can do this by:

export HYDRA_PROXY=socks4://

The other way to use is proxychains. I have done an article about this here if you want to learn more about it. Sadly, TOR will not work.


If you want to resume your hydra session use hydra -R

If you want more information about a specific module use the flag -U.

└─$ hydra https-get-form -U
Hydra v9.3 (c) 2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra ( starting at 2022-06-16 21:08:17

Help for module https-get-form:
Module http-get-form requires the page and the parameters for the web form.

By default this module is configured to follow a maximum of 5 redirections in
a row. It always gathers a new cookie from the same URL without variables
The parameters take three ":" separated values, plus optional values.
(Note: if you need a colon in the option string as value, escape it with "\:", but do not escape a "\" with "\\".)

Syntax:   <url>:<form parameters>:<condition string>[:<optional>[:<optional>]
First is the page on the server to GET or POST to (URL).
Second is the POST/GET variables (taken from either the browser, proxy, etc.
 with url-encoded (resp. base64-encoded) usernames and passwords being replaced in the
 "^USER^" (resp. "^USER64^") and "^PASS^" (resp. "^PASS64^") placeholders (FORM PARAMETERS)
Third is the string that it checks for an *invalid* login (by default)
 Invalid condition login check can be preceded by "F=", successful condition
 login check must be preceded by "S=".
 This is where most people get it wrong. You have to check the webapp what a
 failed string looks like and put it in this parameter!
The following parameters are optional:
 (c|C)=/page/uri     to define a different page to gather initial cookies from
 (g|G)=              skip pre-requests - only use this when no pre-cookies are required
 (h|H)=My-Hdr\: foo   to send a user defined HTTP header with each request
                 ^USER[64]^ and ^PASS[64]^ can also be put into these headers!
                 Note: 'h' will add the user-defined header at the end
                 regardless it's already being sent by Hydra or not.
                 'H' will replace the value of that header if it exists, by the
                 one supplied by the user, or add the header at the end
Note that if you are going to put colons (:) in your headers you should escape them with a backslash (\).
 All colons that are not option separators should be escaped (see the examples above and below).
 You can specify a header without escaping the colons, but that way you will not be able to put colons
 in the header value itself, as they will be interpreted by hydra as option separators.

 "/:user=^USER&pass=^PASS^:failed:H=Authorization\: Basic dT1w:H=Cookie\: sessid=aaaa:h=X-User\: ^USER^:H=User-Agent\: wget"