This post is a "how to" for the "brute force" module set to "low" level security inside of Damn Vulnerable Web Application (DVWA). There are separate posts for the medium level (time delay) and high setting (CSRF tokens). There is a related post for the login screen as it was also brute forced (HTTP POST form with CSRF tokens).
Once more, let's forget the credentials we used to login to DVWA with (admin
:password
).
Let's not try the default login for the web application.
Let's play dumb and brute force DVWA... again.
TL;DR: Quick copy/paste
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Objectives
- The goal is to brute force an HTTP login page.
- GET requests are made via a form.
- The web page is in a sub folder.
- Low
- Straight forward HTTP GET brute force attack via a web form.
- Bonus: SQL injection (
See here for more information).
- Medium
- Extends on the "low" level - HTTP GET attack via a web form.
- Adds in a static time delay (3 seconds) on failed logins.
- High
- Extends on the "low" level - HTTP GET attack via a web form.
- This time uses a random time delay (between 0 and 4 seconds) instead.
- Uses an anti Cross-Site Request Forgery (CSRF) token.
Impossible- Submits data via HTTP POST via web form
- Accounts will lock out after 5 failed logins.
- Time delay before becoming unlocked (15 minutes).
- Unable to enumerate users on the system.
- Possible "Denial of Service (DoS)" vector.
PHPIDS- Does not protect against this attack.
- All attack methods are still the same!
Setup
- Main target: DVWA v1.10 (Running on
Windows Server 2012 Standard ENG x64
+IIS 8
).- Target setup does not matter too much for this -
Debian
/Arch Linux
/Windows
,Apache
/Nginx
/IIS
,PHP v5.x
, orMySQL
/MariaDB
. - The main target is on the IP (
192.168.1.44
), port (80
) and subfolder (/DVWA/
), which is known ahead of time. - Because the target is Windows, it does not matter about case sensitive URL requests (
/DVWA/
vs/dvwa/
).
- Target setup does not matter too much for this -
- Attacker: Kali Linux v2 (+ Personal Custom Post-install Script).
Both machines are running inside a Virtual Machine (VMware ESXi).
Tools
- cURL - Information gathering (used for viewing source code & to automate generating sessions).
- Could also use wget (
wget -qO -
) instead. - Or using Burp/Iceweasel, however, it is harder to automate them due to them being graphical, which makes doing repetitive stuff boring.
- Could also use wget (
- THC-Hydra v8.1 - A brute force tool.
- Patator v0.5 - An alternative brute force tool.
- Burp Proxy v16.0.1 - Debugging requests & brute force tool
- Using FoxyProxy to switch proxy profiles in Iceweasel.
- SecLists - General wordlists.
- These are common, default and small wordlists.
- Instead of using a custom built wordlist, which has been crafted for our target (e.g. generated with CeWL).
- Failed brute force tools:
- Medusa v2.1.1 - segmentation faults when sending a custom header and HTTP 200 response.
- Metasploit v4.11.4-2015090201 -
auxiliary/scanner/http/http_login
does HTTP basic authentication, not web forms. - Ncrack v0.4 ALPHA - HTTP module only supports HTTP basic access authentication, not web forms.
- Nmap v6.49 BETA5 -
http-form-brute
lacks required options to-do the attack (as it cannot send custom headers).
What is brute force?
For the people who are unaware of "brute force attacks", here is an overview of the most common points:
- Brute forcing is a trial and error method of repeatedly trying out a task, sequentially changing a value each time, until a certain result is achieved.
- So it forces its way in, and does not take "no" for an answer.
- The values used in the attack may be predefined in a file (often called a wordlist or dictionary file - there is not a difference between terms), where only these certain values are used. Alternatively, every possible combination could be used in a given range. Example:
- Brute force attack:
AAA
->AAB
->AAC
-> ... ->ZZY
->ZZZ
- Dictionary attack:
ANT
->BED
->CCC
->DOG
->EEE
->HOG
- Brute force attack:
- The values used & the order of them, all depends on how the attacker performs the attack.
- A brute force attack will cover everything in its range; however, it will take longer than a dictionary attack based on the total amount of combinations.
- A dictionary attack will use the pre-compiled values. However, there are values tools out there to "mangle" the wordlist in various ways, allowing for more possibilities and total combinations. An example:
password
->password1999
(year at the end).password
->p@$$w0rd
(1337 speak). The original value (password
) is called "base word". - The best wordlist to use is one customized to the target. When using general wordlists, check for:
- Leading/trailing spaces/tabs -
^ password$
,^password$
,^password $
(forgive the regular expressions!) - Duplicated entries (case sensitive!) -
password
,farm
,PASSWORD
,mouse
,password
,horse
,Password
- The ordering of the list -
common_password
,uncommon_password
- If it is just base words -
password
,password99
,password1999
,p@55w0rd
- The language -
password
,motdepasse
,passwort
,clave
- Leading/trailing spaces/tabs -
- In a brute force attack, multiple wordlists could be used. Example: one for the password, one for the username. The attacker may loop through all the passwords, before trying the next username or vice versa. Alternatively, the username and password lists may be increased at the same time.
- An online attack refers to the attack being a network service, on a machine which is not the attacker's (aka a "remote machine"). An offline attack would be local to the attacker's machine.
- A brute force attack speed runs at the slowest point. If it is an online attack, this is often the network connection, whereas, offline is commonly the CPU/GPU speed. Offline attacks are normally much quicker than online ones.
- There are various ways to speed up brute force attacks, normally by increasing threads. This is how many tasks/requests are performed at once. Not using enough, means there could be additional performance gained as not all the resources are being used. However, using too many will overload causing, it to perform slower or to miss a successful attempt.
Creating a Session Cookie
To get the web form that we want to brute force (http://192.168.1.44/DVWA/vulnerabilities/brute/
), we must already be logged in. This in itself is a bit of an odd thing to-do as most of the time, you would not be authenticated hence the brute forcing... Anyway, as we are going to be using a lot of command line tools, we need to create an active and valid session to interact with DVWA. Normally, you would not have to-do this. This is just for DVWA.
I'm going to be re-running these commands often, however, this is overkill. This is because it will make it easier for people who are copying/pasting or stop/starting a lot (hence their session times out) or people jumping around the page (skipping sections out). As long as the admin
's password has not been changed from the default value (password
), this will work (depending on your target's IP address).
1 2 3 4 5 6 |
|
Note, depending on the web server & its configuration, it may respond slightly differently (in the screenshot: 192.168.1.11
is Nginx,192.168.1.22
is Apache & 192.168.1.44
is IIS). This is a possible method to fingerprint an IIS web server.
The first line grabs the "Anti Cross-Site Request Forgery (CSRF)" token (as explained when brute forcing the main login page), and extracts the user_token
field) which will be a unique value each time and paired to the session ID. We then send a request that would be the same as filling in the form with the user credentials (again, see the main login page being brute forced to see how this was constructed), using the same cookie which was set from our first request. Lastly we remove the security level from the cookie value. As this would be a "static" value, and ideally we want it to be "dynamic" (so we can change the level based in our request).
Information Gathering
If this was a "real world" scenario, we would clone the target's production setup as best we could (e.g. find if it is using "off the shelf" software, web server information, what versions etc.) and clone it into a test lab. This means we could fully control the web application, allowing us to understand it better. For example, we could create a user on the system and watch how the program responses with a successful login, rather than just guessing and hoping.
However, we will take a slightly different approach as this shows why doing information gathering as you go along is important as well using different techniques and methods.
Form HTML Code
The first thing we want to-do is to see what we are going up against. Same idea as before; let's see the returned HTML code. This is done by using sed
to extract between the HTML tags we want (known ahead of time).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
sed -n '/<div class="body_padded/,/<\/div/p'
extracts everything between<div class="body_padded
and its matching</div
. I knew to use these values as I had looked at the complete page output beforehand, the HTML output is far too long, hence whysed
is used to snip out the necessary lines!sed -n '/<form/,/<\/form/p'
is then done as this is everything which would be sent in the request when trying to login.
Generating a Baseline
Now we are going to create a "baseline" which is a request before we try to login (before.txt
), and then make another request made afterwards using an incorrect login attempt (after.txt
). The last step would be to compare the differences between them. This way we can see how the web app responds and start to get a feel of how it works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Note, both requests were made within a second of each other, because of this there the time and date stamp are the same!
Well this is not exactly what we were expecting! One request says the login is incorrect (after.txt
), the other (before.txt
) says we are logged in - yet we did not attempt to! A possible reason for this could because of the cURL
command before, logging us into the core DVWA rather than us using the brute force form. We can confirm our suspicions by making another baseline request.
"Bash fu" alert, we can repeat the last cURL command (!curl
), and replace a value (:gs/after/again/
). People using ZSH shells will also find it will expand the command before executing it. Another tip, by using before{,_again}.txt
our shell will see it as bash.txt before.txt before_again.txt
which saves us typing a bit!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Just as we thought, the You have logged in as 'admin'
message is the core DVWA response rather than the brute force module so we need to ignore this for the brute force module.
Test lab vs Production target
TL;DR: In a test lab, you will have full administrative access. A production target, you may not even have an account to the system.
Even though DVWA is a "test lab", we are treating it as a production target system. Because it is a "black box test", we have not been given credentials to login. The web application does not have a "sign up/register" page so we cannot create a user for ourselves. We could try phish a user to get their login, however, this starts to go out of scope, as it is not really brute forcing.
If DVWA was in a test lab (so we fully control the target, allowing us to created a user ourselves, meaning we know the values to use), or we knew of a valid account to login with on the production server (e.g. default user, demo account, or a given one in the scope of the pentest), we could find a "marker" to signal what happens when you log in (such as output on the page being redirected to a different page, the page size being different, additional headers etc.).
For demonstration purposes, I will show this. First cURL command will remove the unwanted text. The next request is a "failed" log in (user:pass
), the last is successful (admin:password
). By comparing the responses, we can see the page size is different (failed: 4945
, success: 5007
), as well as the HTML output (failed: Username and/or password incorrect.
, success: Welcome to the password protected area
).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Blacklisting vs Whitelisting
TL;DR: Blacklisting, you are ignoring all results that do not contain phrase. Whitelisting, you are looking for a specific value to be successful.
We need to identify a key point to "mark" how the web application will respond when a login is incorrect (aka blackisting) or if it was successful (aka whitelisting).
Blacklisting often contains more false positives, where it believes it has successfully logged in, when it really failed. This is because you have to rule out "every" possible combination other than a successful login. Depending on the web application, it may respond differently for any number of reasons at any stage. If the marker does not appear on the page, it will believe it logged in correctly. An example: if the marker was set to incorrect password
, or if the web app responded with incorrect username/password
because it is not an exact match, the program will believe it is a correct login. If the web application responded with incorrect CSRF token
, the program would believe it was a successful login, even though it was not. Using incorrect
would be better here as it appears in both statements. However, if the marker is too general, this may cause issues. The marker needs to be as unique as possible.
The advantage of using blacklisting is that it is easier to discover a failed login attempt rather than a successful one, so it is easier to begin with. Another benefit is, you get to see how the web application responds differently over time and all responses. This means it is easier to debug issues more quickly.
For whitelisting, they give a more accurate way of knowing if you have logged in correctly, rather than having to rule out every response which is incorrect. The down side to it is if, during the request the page starts to respond differently, we might not be aware, and will just blindly keep attacking, which might be a waste of time. An example is, if an API key has reached its maximum amount of requests for a given period of time.
The "best" way would be to use a mixture of them; ignore all pages that respond in a certain way, print pages which do not match any known response, and quit if a certain value is found (Hydra does not support this, but Patator supports various operators and condition requirements).
Anyway... Getting back to DVWA brute forcing, we could risk doing a whitelist attack and make an educated guess at the response (such as: welcome
, logged in
, successful
, hello
, thank you
etc.), as we do not know what a correct login looks like (because we are ignoring the section above). However, this means we might have to wait as we make multiple complete attempts and also hope a user's password is in our wordlist. So rather than guessing, let's use what we know, (and understand the attack might not work due to an unknown page response, and having to repeat it).
This means we can use either the HTML output of Username and/or password incorrect.
, or the page length being 4945
as markers to ignore. As the HTML is more of a unique marker, we will start by using that (sometimes web applications put various statics in the response, such as page generation time, or a full data stamp which may cause the page length to be different each request - comparing multiple reponses could rule this out). This means any pages which do contain it as incorrect. Therefore any pages which do not contain the phrase, will be seen as "successful" (hopefully this is correct and the web app does not start to behave differently). If it does, we will need ether to also include the additional value or to re-think the marker completely.
Usernames & Wordlists
Normally, people are after the "main" user account on the system (often called admin
, root
, system
), as this is the account that normally has most access over the system. Often this has user id "1" as it is the "first" user account on the system. Depending on the web application there might be "group" control, allowing multiple users to share certain values. If this is the case, there is often an "administrative" group control which is desirable to attackers, which will be a good alterative if the main account is inaccessible.
So during our attacks, we will do two commands. One for a "single user", where we try for the main account (in DVWA case, admin
), and then another command to attack multiple users. DVWA by default comes with a total of five accounts. We want to target them all!
We have crafted a username wordlist ourselves. How do we know what values? Depends on the web application! There are various ways to enumerate users on the system (Are they made public at all? Are we able to exact anything from "Forgotten user password"? Can we map "User IDs" to usernames? Email addresses? Can we just "guest"?). However, in this case, for DVWA:
- There is not a list of public usernames on the web applications.
- There is not a "sign up" or "forgotten password" function.
- Being an end user - we are able to map User IDs to first/last names (not usernames) by a core function in the web application using the "SQL injection module".
- Using this, we could start to build up a custom username wordlist.
- Example: user id:
2
, First name:Gordon
, Surname:Brown
. - This would be all the information need to figure out his uname is:
gordonb
(<surname><first letter of first name>
).
- Web application is free & open source. Looking at the source code, there are five default accounts, hardcoded into the setup (and passwords in plain text).
- Some are usernames hinted at in the "help page".
- There is also a SQL injection in the page (when on low security level):
- Able to enumerate the whole user database (get a list of usernames).
- Extract the hash value of the passwords (allowing for offline brute force attack, which is MUCH quicker than online brute force).
- Replace the hashes with known values.
...more about this later.
A wordlist (sometimes referred to as a dictionary file) is just a plain text file, which contains possible values to try separated out by a common perimeter (often a new line). The file extension does not matter for the text file (often they are .lst
, .dic
, .txt
or missing completely)!
We are going to cycle through the usernames before trying the next password, allowing us to focus on the password. This is an in-built feature in Hydra (-u
), and Patator supports this based on the ID value of the wordlist. It will not matter if there is a single user in the attack, only when trying multiple usernames. The reason why this could speed up an attack is, (un)fortunately people (still) use common passwords. Different users may have the same password as they do not have to be unique (whereas usernames do). e.g. this means every user who has password
as their password, will be discovered very close together.
Threads & Timeouts
TL;DR: Depends on your network connection & target machine. There is not often a need to alter it from default values (unless trying to debug)
Brute forcing is slow. The speed will be because of the slowest point in the system, and there are various places where it will slow down.
- System resources
- Applies to both for the attacker and target machine
- Researched CPU limit? Maxed out on RAM? Hard drive input/output rate?
- Network speed (both up/down stream of both parties)
- What is the target?
- What is the service? (HTTP? SSH? FTP?)
- What is the application? (Open source? Custom made?)
- Does it use a database? Is it local to the target? How many requests does the application make to the database?
- What functions does the application perform? (E.g. calculating password hashes. Certain ones can be more demanding, therefore, increasing the work load).
- Any other users, using the target at the same time?
- Port exhaustion? Can the target handle all those requests?
...and all of this is before any brute force protection is in place (e.g. firewalls, account lockouts etc.)!
Because the amount of requests is username
* password
, the total requests can quickly grow, therefore taking much longer to complete. This is a reason why information gathering & profiling is useful, to know the exact username(s) to target (rather than just guessing). Thereforce using custom built wordlists should give a higher success rate than using a general one (e.g. the chance of a target's password being in an English 65GB wordlist is low if the target does not speak English/have an English keyboard).
Due to the amount of time it may possibly take, there is an urge to tweak the brute force method (e.g. increase the thread count, lower the wait time). However, there is not a fixed "magic number" (it is more of an "art", than a "science"). Altering these values too much, may cause more issues in the long run.
Example: putting the thread count "too high", could cause an extreme amount of requests to a web server. An issue could be the attacker is able to product more network traffic than the target OS/application can handle. Another thing could be, for each request the OS sets aside a certain amount of system resources and soon the target system may run out of memory. It all depends on the setup, the target, and, its configuration. The more requests sent to the target, the harder it has to work, therefore, the response time will start to be slower (so the wait time/timeout values would also need to be increased).
If everything is working "correctly" lowering the wait time does not often archive anything. Example: if the timeout is set to 10 seconds, but it takes less than 1 second to respond, having it at 5 seconds or even 3 seconds will not make any difference. On one hand, having the value too low could mean valid requests are ignored. However, if there starts to be an increase in requests requests taking a longer period of time to response back, for whatever reason, you may be waiting unnecessary (this could signal there is another issue/protection in place).
Another thing to keep in mind, depending on the tool used, it may not display if a request "timed out" or even check periodically to see if the service is still active. Meaning the part of the attack could be pointless.
The last point is, the system may respond differently depending "how it pushed" and "how much it was pushed".
Instead, what might be a better methodology, is having the wordlist sorted in a certain order. This may help speed up the attack (having the more common values at the start). There are various ways to create a custom targeted wordlist, but this going offtopic. Just bare in mind, you may not have to go through the complete wordlist, there is a 50% chance it will be in the first half ;-).
It might also mean taking multiple runs for it to be successful, one at once (serial rather than parallel). E.g. one wordlist with default credentials, another with commonly used passwords, and another with just a baseline wordlist then another try with "mangled rule" applied to the prior1 wordlist. So each time the size of the wordlist would grow, taking longer, but there will be less chance of missing the "low hanging fruit". I believe it is "better" to make lots of smaller attacks rather than being lazy and making one big one.
During the debugging stage, I used a single thread (so it is easier to follow the request in a proxy/watching web logs), with a larger timeout value (as I could then tweak the values in Burp's intercept screen), and added in a delay after the thread finished (so I could check all the output). For the "final" attack, I was on a LAN connection, rather than WAN/Internet, therefore, the speeds would be quicker. Because the response times were so low, the slowest point normally was not the network connection (therefore increasing the threads would not help a great deal in this case). See the benchmark results!
Getting the attack to use the maximum performance first time is rare =).
Hydra
Hydra Documentation
First tool we are going to use is THC-Hydra
(more commonly known as just Hydra
). This is probably the "most well-known" tool (as it has been around since August 2000 with the public release of v0.3). Since Hydra has been around for so long, it supports a very wide range of modules/attack methods in any tool, and it is still getting updates!
Here are snippets from the documentation (readme.txt
, help screens: hydra -h
& hydra -U http-post-form
, & man page: man hydra
).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Debugging Hydra with Burp Proxy
We could use wireshark
or tcpdump
to monitor what is sent to and from Hydra, as well as use the in-built "debug" flag (-d
). However, the issue with all of these is there is an awful lot of data put on the screen, which makes it harder to understand what is going on.
Incomes the use of a "proxy". Rather than it being used in an attempt to "hide your IP" (by using another machine fisrt in order to connect to the target, instead of going directt), we can use it to inspect the traffic. Using Burp Proxy Suite
, we can monitor what is being sent to and from our target. This way we can check to see if Hydra is acting in our desired way and reacts correctly when there is a successful login. By using Burp, we are able to quickly filter, sort and compare all of the requests. It is also worth noting that Hydra does come with a verbose option (-v
) to display more information than standard, but not as much as debug!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Let's break down the lines:
rm -f hydra.restore;
- when you break from Hydra before the brute force attack is complete, it will automatically create a session file, allowing you to restore. We do not want that now.export HYDRA_PROXY_HTTP=http://127.0.0.1:8080
- this is a bash variable that instructs Hydra to use a proxy.hydra
- the main program itself-l admin
- a single static username,admin
.-p password
- a single static username,password
.-e ns
- try a "null" password for the user & "same" username as password-F
- quit after logging in successfully-t 1
- single thread-w 5
- timeout value of 5 seconds-W 1
- wait 1 second before going on to the next thread-v
- enable verbose-V
- show login attempts (will print out username and password combinations)192.168.1.44
- the target IPhttp-get-form
- the module to use for the method of the attack"/DVWA/vulnerabilities/brute/
- the path to the web form to target:username=^USER^&password=^PASS^&Login=Login
- how to use the wordlists in the request.:F=Username and/or password incorrect.
- Failed logins will contain the following string (aka blacklisting)- If we wanted to use the page length instead:
:F=Content-Length\: 4945
- If we wanted to use the page length instead:
:H=Cookie\: security=low; PHPSESSID=${SESSIONID}"
- the cookie information to send.
Becuase we are debugging, the thread count is set to 1, using a larger timeout value as well as to wait after each thread finishes. This is because, when there are multiple requests being made without any delay, it makes it harder managed and to track Hydra's progress inside of Burp.
Note, if we are going to use Burp, make sure "Invisible Proxy Mode" is enabled (see below)!
Burp's Invisible Proxy Mode
TL;DR: Enable Burp's "Invisible Proxy Mode" when using Hydra.
<rambles>
- I noticed when I made the first request, Burp did not detect any GET parameters in the URL. They were missing (e.g.
?username=...
). - Checking the web logs on the target, I saw that the parameters were definitely not making it to the target's web server.
- As I could see the combinations attempts (
-V
), Hydra believes that it was sending out the correct combinations. So the next option was using the debug command,-d
.
- After sifting through the debug data, Hydra itself was reporting that it successfully sent out the URL with the GET parameters. This meant there was an issue between Hydra and the proxy/Burp.
- Disabling the proxy usage, and switching to
wireshark
to monitor the traffic, this time, the traffic appeared to be correct. This was confirmed by the web server logs!
- Re-enabling the proxy, but this time switching to OWASP Zed Attack Proxy (instead of Burp) was also working.
- After contact Burp support, they suggested to look at the "alert tab" and report back anything displayed there. This contained a key bit of information, which led to the fix. Oops!
- Now, I changed the mode of the proxy type to be "Invisible". See here for more information about Invisible Proxying
- The result is successful! Both Burp and the web logs now show the valid GET parameters!
Please note, S=INCORRECT_VALUE
was used, rather than F=Username and/or password incorrect.
as I wanted Hydra to guarantee not to find a valid login. If F=...
was used, because the page would not contain the value (due to Invisible Proxy Mode not being enabled), Hydra assumed it got it right, on the first attempt.
</rambles>
Summary:
There are three solutions for this:
- Do not use a proxy with Hydra (
unset HYDRA_PROXY_HTTP
). - Use a different proxy (OWASP ZAP works out of the box).
- Enable "invisible proxy mode" when using in Burp as a proxy.
So now it is time to start the attack.
Hydra Attack Command
The top code snippet, will brute force a single user, the admin
user and then stop the attack when the user is found (-F
). It will also show all combination attempts (-V
) as well as blacklisting a certain phrase (a successful login will NOT contain this value).
The bottom one will brute force all five users (which are thereby default in DVWA), but will take much longer (as there are many more combinations to try). A different wordlist is used (both for usernames and passwords) and higher threads & timeout values. It will also not display combination attempts (missing -V
). Rather than looking for a page that does not include a certain value, this time look for a certain phrase once we are logged in (whitelisting). More about blacklisting vs whitelisting at the end.
Single User - admin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Multiple Users
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
A few comments when using hydra in multiple user mode:
- Once Hydra finds the last credential to brute force, it will quit.
- I also found when doing any more than 3 threads, once the last user account was cracked, all but one process thread would finish and the remaining one would start to increase CPU usage (it also stopped sending out requests).
- It is using whitelisting rather than blacklisting.
- Could not use
:S=Content-Length\: 5007
as the page length if it was a successful login as the page will be a different sized based on the username who logged in. Hydra does not support maths functions to say less than or greater than (currently in v8.1).
Patator
Patator Documentation
Patator is not as well-known as either Hydra, Medusa, Ncrack, Metasploit, or Nmap probably due to the it being the "youngest" tool (In November 2011 v0.1 was released publicly).
Quoting the README file: "Patator is NOT script-kiddie friendly, please read the README inside patator.py before reporting."
Patator is incredibly powerful. It is written in python, rather than C (which makes Patator use more system resources), however, it makes up for this as it has an it has an awful lot more features and options. It is not straightforward to use, and there is limited documentation for it. But I personally find it is worth investing the time to use it =).
Once again, let us read up, what does what, and think about what we need.
1 2 3 4 |
|
The README also states to check the comments in the code (there is some unique information located here). I also found checking the actual source code to be helpful as it gave me a better understanding. It is written in Python, which makes it easier to understand.
Offline: less $(which patator)
Online: https://github.com/lanjelot/patator/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Debugging Patator
Patator is more verbose in its output compared to Hydra, as out of the box Patator will display all attempts made (you need to tell it to ignore requests based on a parameter). Plus, it will have various columns displaying results (which thread made the request, size of response, code response etc.), in every visible request. This helps to build up a bigger picture overall of what is going on with the attack. Patator has more of a "fuzzer" feel to it, rather than being a brute force tool.
Unless you tell it not to, Patator will not only do it but display the result of it and keep on doing it until instructed otherwise.
For whatever reason, if the displayed output is not enough, then Patator can be put through a proxy to monitor its actions (Burp does not need to be in "Invisible Proxy Mode".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Again, let's break down the command (also at the end, I will make a comparison between Hydra and Patator syntaxes):
patator
- the main program itselfhttp_fuzz
- the module to use for the method of the attackmethod=GET
- how to send the requesturl="http://192.168.1.44/DVWA/vulnerabilities/brute/?username=admin&password=FILE0&Login=Login"
- the full URL and how to use the wordlist0=/root/password.txt
- defining the file for "wordlist 0" (aka password wordlist)header="Cookie: security=low; PHPSESSID=${SESSIONID}"
- the cookie information to send.http_proxy=127.0.0.1:8080
- instructs Patator to use a proxy.--threads=1
- single threadtimeout=5
- timeout value of 5 seconds--rate-limit=1
- wait 1 second before going on to the next thread-x ignore:fgrep='Username and/or password incorrect.'
- If it matches, do not display out. All Failed logins will contain this string (aka blacklisting)-x quit:fgrep!='Username and/or password incorrect.'
- If it does not match this string on the page, quit.- If we wanted to use the page length instead:
-x ignore:clen=4945
.
- If we wanted to use the page length instead:
,clen!='-1'
- this extends the conditions required quit (AND operator). The page response length cannot be-1
(aka the page timed out).
You may have noticed, we had to create a wordlist to match the same values that were sent when using Hydra. This is because Patator does not (yet?) support Hydra's -e nsr
options to send a blank password, the username as the password or reverse the login.
Unlike Hydra, Patator does NOT say "successfully logged into host: 192.168.1.44, login: admin, password: password". It is up to US to define the information we want shown (or not wanted). Patator will also keep on just "going through" the wordlist(s) until it reaches the end (again, it is up to us to define a breaking point). With this in mind, this is what we have done:
-x ignore:fgrep='Username...
- means "do not display anything which matches this" (due to bad login)-x quit:fgrep!='Username...
- means "quit the attack if the page does not match" (due to successful login)- As this is a password single user brute force, it does not make too much sense to keep going as a user only has one password (normally?)
- This enforces why it is a fuzzer, rather than a password brute force tool (and a reason why it is harder to use).
,clen!='-1'
- and extend the quit condition so the content length cannot equal-1
(which is the value for pages that timeout).
Patator Attack Command
Single User - admin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
To match the brute force attempt of Hydra, where it was displaying the values tried, -x ignore:fgrep='Username and/or password incorrect.'
was not used. You can see what the correct value was to login (password
), based on the "page size:content length" reported back (5276:5007
), The first value is also different due to the extra line added in from DVWA core, which was noted when we did the baseline responses.
Multiple Users
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Note, because the username and password values are hardcoded in the URL for the http_fuzz module, we are unable to use something like -x free:user=...
to skip over the value once there has been a successful login. This means, Patator will keep on making requests with a user after it has already found the password.
Unlike Hydra, we can give a range of Content-Length
values to look for or ignore.
Burp Proxy
Burp Suite has a proxy tool, which is primarily a commercial tool, however, there is a "free license" edition. The free edition contains a limited amount of features and functions with various limits in place, one of which is a slower "intruder" attack speed. Burp Proxy has been around since August 2003.
Burp mainly uses a graphic UI, which makes it harder to demonstrate how to use it (mouse clicking vs copying/pasting commands). This section really could benefit from a video, rather than a screenshot gallery.
Setup
- The first thing we need to-do, setup our web browser (Iceweasel/Firefox) to use Burp's proxy.
- IP:
127.0.0.1
(loopback by Burp's default), Port:8080
- Using FoxyProxy to switch profiles.
- IP:
Burp needs a request to work with. Either we could write one out by hand (which would take a while), or we can capture a valid request and use that.
- Using Iceweasel, make a request in the brute force form.
- Values can be anything, however, in the example: username:
admin
, password:pass
- Values can be anything, however, in the example: username:
- Burp by default will have intercept enabled, allowing us to inspect the request.
- Rather than allowing the request, we will send it to the Intruder
- Actions -> Send to Intruder.
Next, we are telling Burp how to attack the target (using a single wordlist)
- Intruder (tab) -> 2 -> Positions -> Attack type:
sniper
- Single list, going through each value one by one
- For more information about attack types: https://portswigger.net/burp/help/intruder_positions.html
- Press:
Clear §
- Highlight:
password=pass
-> Press:Add §
- Result:
password=§pass§
- Result:
At this stage, we are telling what values to attack with (going to use the original three debugging values)
- Intruder (tab) -> 2 -> Payloads -> Payload Sets
- Payload set:
1
. - Payload type:
Simple list
.
- Payload set:
- Payload Options [Simple list]
- Add:
admin
,<blank>
&password
as three separate values
- Add:
Now we are going to alter the options as to how Burp behaves. This is an optional stage; however, it makes the output easier to see.
Disable the baseline request
- Intruder (tab) -> 2 -> Options -> Untick: Make unmodified baseline request
Extract values from the page: In Burp's results, it will display the following text in the output. See why later.
- Intruder (tab) -> 2 -> Options -> Grep - Extract -> Add
- Fetch Response
- Start after expression:
<pre><br />
- End at delimiter:
</pre>
- Okay
Now we are ready to start the attack!
- Intruder (Top Menu) -> Start attack
Note, there will be an alert explaining that the speed will be limited due to the "free edition" of Burp.
Result: We can see based on the "Length
" and "<pre><br />
", which request (and payload) was "different" (aka a successful login).
Single User - admin
Now, let's pretend we didn't already know what the correct login was and use a wordlist.
- Intruder (tab) -> 2 -> Payloads -> Payload set:
1
. - Payload Options [Simple list]
- Clear.
- Load:
/usr/share/seclists/Passwords/rockyou-5.txt
-> Open
Then, to start the attack (missing a screenshot):
Note, there will be an alert explaining that the speed will be limited due to the "free edition" of Burp.
- Intruder (Top Menu) -> Start attack
Result: Again, you can see the request (and payload) which caused a different result (aka a successful login).
Note, Burp will continue to go through the wordlist until it reaches the end. It will not stop at a "valid login". This might not be the case in later versions (or I missed a method to stop this from happening).
Multiple Users
Now we want to brute force all five users again.
- Intruder (tab) -> 2 -> Positions -> Attack type:
Cluster bomb
.- This supports multiple lists (based on the number of fields in scope. Defined by
§value§
), going through each value one by one in the first wordlist, then when it reaches the end to move to the next value in the next list - For more information about attack types: https://portswigger.net/burp/help/intruder_positions.html
- This supports multiple lists (based on the number of fields in scope. Defined by
- Highlight:
username=admin
-> Press:Add §
- Result:
username=§admin§
- Result:
Let us now define our usernames to use. This is ID 1
as it is the first value (reading left to right, top to bottom).
- Intruder (tab) -> 2 -> Payloads -> Payload set:
1
. - Payload Options [Simple list]
- Clear.
- Load:
/root/users.txt
-> Open
Result: See Burp says "Payload count: 5"
Now we need to load in the passwords to try
- Intruder (tab) -> 2 -> Payloads -> Payload set:
2
. - Payload Options [Simple list]
- Load:
/usr/share/seclists/Passwords/rockyou-45.txt
-> Open
- Load:
Result: Burp says Payload count: 6,164
(5
* 6,164
= 30,820
). This means Burp will make ~31k requests to the target (as it will not "break" on a successful login as well as removing values from the username).
Then, to start the attack (missing in screenshot):
Note, there will be an alert explaining the speed will be limited due to the "free edition" of Burp, including "Time-throttled" & limited to 1 thread. I couldn't find exact details of how "slow", but it is noticeably slower. Speed limits may change in later versions too.
- Intruder (Top Menu) -> Start attack
Result: Because Burp is not fully aware of a successful login, it will not perform any differently (like Patator), as they are both "fuzzing" the web application. This means it will do every user (even after successfully logging in) until the end of the password list. It will try and make every 30,820 requests to the target web application and with the speed limitation in place so this is less than ideal. Note, there is a feature request ticket to include this feature into Burp, so in later versions it may be supported.
Failed Attempts
This is because either I did not use the tool correctly or the tool does not yet support the necessary features and options.
Medusa
TL;DR: Did not get Medusa to work correctly. Just kept segmentation faulting.
Medusa is an older and more well-known brute force tool (I cannot find an exact release date for v1.0, although, v1.1 was reported to be released in May 2006). However, the last stable update was in May 2012, so it does not appear to be under development still.
I personally did not find the syntax as straightforward as Hydra (having to start with -m
), plus it seemed to be lacking a few features (such as proxy support), and add on the fact I couldn't get the program to work correctly, as it would say segmentation fault
on all HTTP 200 responses. If an incorrect cookie was used, it would say: ERROR: The answer was NOT successfully received, understood, and accepted while trying admin admin: error code 302
. I could not see a way to overwrite this without recompiling the program (so this would not have made the login screen brute force impossible).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Nmap
TL;DR: Nmap does have a script which is able to brute force web forms, however, it is unable to set custom headers in the request, so we cannot log into DVWA.
Online: https://nmap.org/nsedoc/scripts/http-form-brute.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Ncrack
TL;DR: Ncrack v0.4ALPHA does not support web forms. It is only able to-do HTTP basic access authentication.
Ncrack was written in 2009, and has not been updated since. Development has been moved into nmap's scripts instead.
Metasploit Framework
TL;DR: Metasploit framework v4.11.4-2015090201 does not support web forms, but rather HTTP basic access authentication (auxiliary/scanner/http/http_login
).
Online: http://www.rapid7.com/db/modules/auxiliary/scanner/http/http_login.
...however, knowing what the development is like, I am sure one day it will be in there ;-).
Proof of Concept Scripts
Here are two Proof of Concept (PoC) scripts (one in Bash and the other is Python). They are really rough templates, and not stable tools to be keep on using. They are not meant to be "fancy" (e.g. no timeouts or no multi-threading). However, they can be fully customised in the attack (such as if we want to use a new anti-CSRF token on each request etc.).
I will put this all on GitHub at the following repository: github.com/g0tmi1k/boot2root-scripts/.
Benchmark
- Bash: ~2.0 seconds
- Python: ~3.4 seconds
Bash Template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
Python Template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
|
Summary
Hydra vs Patator Syntax
This will show the some differences between Hydra and Patator commands:
Main Program:
- THC-Hydra:
hydra
- Patator:
patator
- THC-Hydra:
Single usernames to use:
- Hydra:
-l admin
- Patator: N/A. Happens with in
url="http://192.168.1.44/...
- Hydra:
Single password to use:
- Hydra:
-p password
- Patator: N/A. Happens with in
url="http://192.168.1.44/...
- Hydra:
List of usernames to use:
- Hydra:
-L /usr/share/seclists/Usernames/top_shortlist.txt
- Patator:
0=/usr/share/seclists/Usernames/top_shortlist.txt
- Hydra:
List of passwords to use:
- Hydra:
-P /usr/share/seclists/Passwords/500-worst-passwords.txt
- Patator:
1=/usr/share/seclists/Passwords/500-worst-passwords.txt
- Hydra:
Use empty passwords/repeat username as password
- Hydra:
-e ns
- Patator: N/A. Does not have the option.
- Hydra:
Try all the passwords, before trying the next password
- Hydra:
-u
- Patator: The password wordlist (
FILE0
) has a lower ID than the username wordlist (FILE1
).
- Hydra:
Quit after finding a valid login
- Hydra:
-F
- Patator:
-x quit:...
. More about this later.
- Hydra:
Limit the threads
- Hydra:
-t 1
- Patator:
--threads=1
- Hydra:
Timeout value on request
- Hydra:
-w 1
- Patator:
timeout=1
- Hydra:
Timeout before starting next thread
- Hydra:
-W 1
- Patator:
--rate-limit=1
- Hydra:
Verbose (aka show redirects)
- Hydra:
-v
- Patator: N/A. Does it out of the box (To hide them:
-x ignore:code='301'
).
- Hydra:
Show password attempts
- Hydra:
-V
- Patator: N/A. Does it out of the box (To hide them:
-x ignore:fgrep='Username and/or password incorrect.'
).
- Hydra:
The target to attack
- Hydra:
192.168.1.44
- Patator: N/A. Happens later (
url="http://192.168.1.44/DVWA/login.php"...
)
- Hydra:
Module to use
- Hydra:
http-get-form
- Patator:
http_fuzz
- Hydra:
How to transmit the data
- Hydra: N/A. It is done in the module name. (
http-get-form
) - Patator:
method=GET
- Hydra: N/A. It is done in the module name. (
Web page to attack
- Hydra:
"/DVWA/login.php:
- Patator:
url="http://192.168.1.44/DVWA/vulnerabilities/brute/?username=FILE1&password=FILE0&Login=Login"
- Hydra:
GET data to send
- Hydra:
username=^USER^&password=^PASS^&Login=Login
- Patator: N/A. Happens with in
url="http://192.168.1.44/...
- Hydra:
Cookie/Header data to send
- Hydra:
:H=Cookie: security=low; PHPSESSID=${SESSIONID}
- Patator:
header="Cookie: security=low; PHPSESSID=${SESSIONID}"
- Hydra:
Whitelist page response
- Hydra:
:S=Welcome to the password protected area
- Patator #1:
-x quit:fgrep="Welcome to the password protected area"
. Quit when this value is found the first time. - Patator #2:
-x ignore:fgrep!="Welcome to the password protected area"
. Only display pages which do match.
- Hydra:
Blacklist page response
- Hydra:
:F=Username and/or password incorrect.
- Patator #1:
-x quit:fgrep!='Username and/or password incorrect.'
. Quit as soon as this is NOT found. - Patator #2:
-x ignore:fgrep='Username and/or password incorrect.'
. Only print pages which do NOT match.
- Hydra:
Blacklist page length of
4945
- Hydra:
:F=Content-Length\: 4945
- Patator:
-x ignore:clen=4945
- Hydra:
AND operator
- Hydra: N/A. Does not have the feature.
- Patator:
,clen!='...
Do not follow requests
- Hydra: N/A. Have to use a proxy in line with it.
- Patator:
follow=0
Do not accept cookies
- Hydra: N/A. Have to use a proxy in line with it.
- Patator:
accept_cookie=0
Use in a HTTP proxy
- Hydra:
export HYDRA_PROXY_HTTP=http://127.0.0.1:8080
- Patator:
http_proxy=127.0.0.1:8080
- Hydra:
Amount of retires to perform
- Hydra: N/A. Does not have the feature.
- Patator:
--max-retries=0
Visit a page before the request, to get a input to use as a value (aka anti-CSRF bypassing)
- Hydra: N/A. Does not have the exact feature (closest is:
:C=/page_to_get_cookie_value_only
) - Patator:
before_urls="http://.../" before_egrep="_CSRF_:<input type='hidden' name='csrf_token' value='(\w+)' />"
- Hydra: N/A. Does not have the exact feature (closest is:
Benchmark
Each test was repeated three times and the average value was taken. The value displayed are in seconds. The password wordlist used was /usr/share/seclists/Passwords/passwords_clarkson_82.txt
(which is a poor wordlist for the record), and /usr/share/seclists/Usernames/top_shortlist.txt
for the usernames. Both Hydra and Patator will stop when they find the first (and only) valid user (admin:password
). This means they will produce 508 requests in order to find the successful account. In addition, there was not any waiting between threads ending. There were two different timeout values used (3 seconds and 10 seconds), which is shown in the tables below.
Hardware & Software:
192.168.1.11
- Raspberry Pi v1 "B" Arch Linux // Nginx v1.8.0 // PHP v5.6.14 // MariaDB v10.0.21192.168.1.22
- Raspberry Pi v2 "B" Raspbian // Apache v2.4.10 // PHP v5.6.13 // MySQL v5.5.44192.168.1.33
- Windows XP SP3 (VM: 1 Core/512 MB) // Apache v2.4.10 (XAMPP v1.8.2) // PHP v5.4.31 // MySQL v5.5.39192.168.1.44
- Windows Server 2012 (VM: 1 Core/2048 MB) // IIS v8.0 // PHP v5.6.0 // MySQL v5.5.45
Results: (With 3 seconds timeout)
HYDRA | 192.168.1.11 | 192.168.1.22 | 192.168.1.33 | 192.168.1.44 |
---|---|---|---|---|
1 Thread | 152 | 67 | 79 | 36 |
2 Threads | 141 | 49 | - | 38 |
4 Threads | 140 | 49 | - | 36 |
8 Threads | 140 | 47 | - | 36 |
16 Threads | - | 44[*] | - | 39 |
32 Threads | - | - | - | 45 |
------------- | ------------------ | ------------------ | ------------------ | ------------------ |
PATATOR | 192.168.1.11 | 192.168.1.22 | 192.168.1.33 | 192.168.1.44 |
---|---|---|---|---|
1 Thread | 72 | 28 | 43 | 18 |
2 Threads | 69 | 24 | - | 19 |
4 Threads | 69 | 26 | - | 19 |
8 Threads | 70 | 18 | - | 19 |
16 Threads | - | 26 | - | 19 |
32 Threads | - | 43[**] | - | 22 |
------------- | ------------------ | ------------------ | ------------------ | ------------------ |
- [*] == One pass did not not find the password.
- [**] == More than one thread timeout, but still found the password.
Results: (With 10 seconds timeout)
HYDRA | 192.168.1.11 | 192.168.1.22 | 192.168.1.33 | 192.168.1.44 |
---|---|---|---|---|
1 Thread | 162 | 66 | 78 | 39 |
2 Threads | 141 | 48 | - | 42 |
4 Threads | 140 | 49 | - | 38 |
8 Threads | 140 | 50 | - | 41 |
16 Threads | 139 | 49 | - | 41 |
32 Threads | 141 | 49 | - | 44 |
------------- | ------------------ | ------------------ | ------------------ | ------------------ |
PATATOR | 192.168.1.11 | 192.168.1.22 | 192.168.1.33 | 192.168.1.44 |
---|---|---|---|---|
1 Thread | 72 | 32 | 45 | 21 |
2 Threads | 70 | 24 | - | 21 |
4 Threads | 69 | 21 | - | 21 |
8 Threads | 69 | 23 | - | 19 |
16 Threads | 70 | 26 | - | 21 |
32 Threads | 71 | 30 | - | 22 |
------------- | ------------------ | ------------------ | ------------------ | ------------------ |
For the reason why Hydra is noticeable slower than Patator, see the medium level benchmark results.
Further testing:
The benchmark results are only for a single user (even though the username comes from a wordlist). So, how does Hydra & Patator compare when multiple users are brute forced? I believe this is where Hydra would start to outperform Patator as it is able to stop testing a value when a user is found, therefore it will produce less requests overall. The test would be, how many number of successful logins vs the time taken.
Bash Benchmark Command
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Conclusion
None of the tools are not "perfect". I would say there is not a single "go-to tool", as each is better in certain cases.
Hydra at designed to be an "online password brute force tool", and has the features and function we need to-do this type of brute force. However, a more complex one (such as anti-CSRF tokens - which happens later), Hydra will fail at. I found it is the "best" tool to brute force multiple users, as it will produce the least amount of requests.
Patator at its heart is an "online fuzzer", which can be used to fuzz inputs into the username/password fields to brute force. It has many more features and options than Hydra. I believe it is the best tool for brute forcing a single user (or modules which have dedicated username/password field, which was not the case for web form).
Burp Suite is also a fuzzer, as well as offering a lot of other options (it is a multi-tool - hence "suite"). Unless you have a commercial license, the free version will be much slower than the other two options. The upside is, it allows you to-do the most complex brute force attacks (even in the free edition).
That's it! A how to guide on Damn Vulnerable Web Application (DVWA) to brute force the low level using Hydra and Patator (and Burp), with a comparison guide and how to debug issues with a proxy.
curl -s -b 'security=low' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/' | sed -n '/<form/,/<\/form/p' | grep -i "<action"|"<input"
<form action="#" method="GET">
- a GET request to the same URL/DVWA/vulnerabilities/brute/
- Hydra:
http-get-form
- Patator:
http_fuzz method=GET
- Hydra:
<input type="text" name="username"><br />
- username field- Hydra:
username=^USER^
- Patator:
username=FILE1
- Hydra:
<input type="password" AUTOCOMPLETE="off" name="password"><br />
- password- Hydra:
password=^PASS^
- Patator:
username=FILE1
- Hydra:
<input type="submit" value="Login" name="Login">
- action- Hydra:
Login=Login
- Patator:
Login=Login
- Hydra:
- Result:
- Hydar:
/DVWA/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login
- Patator:
/DVWA/vulnerabilities/brute/?username=FILE1&password=FILE0&Login=Login
- Hydar: