Original link: https://blog.g0tmi1k.com/dvwa/bruteforce-medium/
This post is a "how to" guide for Damn Vulnerable Web Application (DVWA)'s brute force module on the medium security level. It is an expansion from the "low" level (which is a straightforward HTTP GET form attack), and then grows into the "high" security post (which involves CSRF tokens). There is also an additional brute force option on the main login screen (consisting of POST redirects and a incorrect anti-CSRF system).
Once again, let's pretend we do not know any credentials for DVWA.
Let's play dumb and brute force DVWA... again ...again!
TL;DR: Quick copy/paste
Table of Contents
Objectives
Setup
Tools
Creating a Session Cookie
Information Gathering
Form HTML Code
Attack Vectors
Minimum Wait Time
Brute Forcing
Hydra
Patator
Summary
Benchmark
Why is Hydra slower than Patator?
Conclusion
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, or MySQL/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/).
Attacker: Kali Linux v2 (+ Personal Custom Post-install Script).
Shell prompt will look different (due to ZSH/Oh-My-ZSH).
Added colour to tools output (thanks to GRC).
Both machines are running inside a Virtual Machine (VMware ESXi).
Tools
cURL - Information gathering (used for viewing source code & to automate generating sessions).
THC-Hydra v8.1 - A brute force tool.
Patator v0.5 - An alternative brute force tool.
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).
Creating a Session Cookie
This was covered in the first post, low level, which will act as a "base" to this post. I'm not going to cover this again, so if things are not clear, I highly suggest you read over the previous post first.
The command has not changed; the target has not changed, so the output and result will be the same as the levels below.
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.
Information Gathering
Form HTML Code
The first thing is, to try and find out what is different (without looking at the server side PHP source code). Using the same commands as before, let's see what the HTML code page is for the web form.
Does not look too different from before, but let's check.
There is nothing different between the pages. Okay, now what happens if we compare responses when logging in incorrectly, with an invalid user credential?
Looking at just the output, other than the core DVWA information, there is not any difference in the brute force module displayed output. However, making the request, there was a noticeable time difference in response times.
It is clear that there is now a three second time delay when trying to login with incorrect credentials. This by itself will not offer brute force protection; however, it might mean it will slow down the brute force speed, increasing the time needed for the attack. The question is, will it also have the time delay on a successful login? Without a valid user credential to login as with, we cannot know this (there is not a "register"/"sign up" page and we were not given any in our pretend scope). What we should now do is setup a cloned environment in a test lab (as the project is free and open source) and either look at the source code or login with our admin account. However, we are going to pretend it is a custom built application so we cannot duplicate the setup. We are also going to skip the "view source" function which is in-built to DVWA's core, allowing us to see how the module works.
Attack Vectors
There are two possible ways we can approach this now. The first method, just as before, is the same brute force command, however, this time make sure the "timeout" value is able to cope with the additional wait delay from DVWA (the 3 seconds cool down) as well as all the threads/system load produced. This means there could be a significant time increase to perform the brute force. Alternatively, what happens if we set the timeout value to be less than three seconds? We would not be able to use a large number of threads (a larger thread count, means more requests, more requests result is the system working harder, therefore taking longer to process our request). This is a possible option and only an option because by using the rest of the site, all our requests take less than a second to load (so it depends on the network connection speed and target performance), therefore we are assuming (and taking an educated guess) that there would not be a delay with a valid login.
So what happens if we make four requests, one after another? This would mean request #2-#4 needs to be sent inside the three second cool down of request #1. Does request #4 only take three seconds to respond back or does it have to wait the additional time of the all the other request's cool down time too? We can find out by doing the following:
Before we execute this, I will explain what is happening (as it will get a little more complex when executed). All of this is a single "command" (even though it is on multiple lines, it is chained together). It can be broken down like so:
date - This will display the date/time for our starting point.
; - Once the previous command finishes, regardless of the exit code, run the next command.
curl -s ... - Make an invalid login attempt to the target.
&- "background" the previous command, allowing the rest of the commands to keep on running without waiting.
\ - instructs bash there is an additional line and not to execute the command just yet.
curl... + & - these are repeated another 3 times (requests #2-#4).
&& - Signals to wait for the previous command to finish. If it was successful, to move onto the next command.
date - Display the end date, when request #4 finishes.
sleep 30s - Wait 30 seconds before doing the next loop. This is to allow all the other requests to finish.
TL;DR: Display the time before starting. On the 4th (and final?) request, display the time again after the cURL command finishes executing. Compare both timestamps.
It is always good practice to repeat a test multiple times, to make sure the results are consistent (Let's forget: "Insanity: doing the same thing over and over again and expecting different results." ~ Albert Einstein).
...Looks like we are not going too crazy, as there were different results!
Loop 1: 12 seconds.
Loop 2: 3 seconds.
Loop 3: 9 seconds.
Unfortunately, this means when we do our brute force attempt we need to allow for the maximum possible wait time. There are no shortcuts; otherwise we may not get reliable results (thus wasting all of our time).
Just because we have finished making requests or brute forcing it, does not mean the web application is still processing requests/cooling down.
Minimum Wait Time
We can calculate the minimum value for the wait time as follows:
The 2 seconds for the leeway amount is a "safe net" in case of there being an additional lag (would need to be higher if based on the slowest point in the attack). Note, in the low security posting the value was set to 3 seconds.
This means there could be a possible extra 11 seconds of wait time between "low" and "medium" when using 4 threads. This is because there is a guaranteed of at least 3 seconds delay for each thread.
Again, if the wait time is too low, it will not find a successful login. See the "low level" for a deeper explanation.
Note, if this was a "live" box in production, which means other users could be using it, what happens if they are failing to login at the same time as we brute force? This might have an effect; is the cool down based upon session values, IP, or complete web application?
Brute Forcing
Hydra
We are using the same arguments as in the low level, however their values may be different.
Debug/Test command:
(1 thread * 3 seconds sleep) + 2 seconds extra = 5 second wait time.
Main Command:
(5 threads * 3 seconds sleep) + 2 seconds sleep = 17 seconds wait time.
Patator
We are using the same arguments as in the low level, however their values may be different.
Debug/Test command:
(1 thread * 3 seconds sleep) + 2 seconds leeway = 5 seconds wait time.
Main Command:
(5 threads * 3 seconds sleep) + 2 seconds safe net = 17 seconds wait time.
[root:~]# CSRF=$(curl -s -c dvwa.cookie "192.168.1.44/DVWA/login.php" | awk -F 'value=' '/user_token/ {print $2}' | cut -d "'" -f2)
[root:~]# SESSIONID=$(grep PHPSESSID dvwa.cookie | cut -d $'\t' -f7)
[root:~]# curl -s -b dvwa.cookie -d "username=admin&password=password&user_token=${CSRF}&Login=Login" "192.168.1.44/DVWA/login.php" >/dev/null
[root:~]#
[root:~]# time patator http_fuzz method=GET \
url="http://192.168.1.44/DVWA/vulnerabilities/brute/?username=FILE1&password=FILE0&Login=Login" \
1=/usr/share/seclists/Usernames/top_shortlist.txt 0=/usr/share/seclists/Passwords/rockyou.txt \
header="Cookie: security=medium; PHPSESSID=${SESSIONID}" \
--threads=5 timeout=17 \
-x quit:fgrep!='Username and/or password incorrect.',clen!='-1'
20:40:03 patator INFO - Starting Patator v0.5 (http://code.google.com/p/patator/) at 2015-10-30 20:40 GMT
20:40:04 patator INFO -
20:40:04 patator INFO - code size:clen | candidate | num | mesg
20:40:04 patator INFO - ----------------------------------------------------------------------
20:40:07 patator INFO - 200 5310:5041 | 123456:info | 5 | HTTP/1.1 200 OK
20:40:10 patator INFO - 200 5223:4954 | 123456:test | 3 | HTTP/1.1 200 OK
20:40:13 patator INFO - 200 5223:4954 | 123456:root | 1 | HTTP/1.1 200 OK
20:40:16 patator INFO - 200 5223:4954 | 123456:guest | 4 | HTTP/1.1 200 OK
20:40:20 patator INFO - 200 5223:4954 | 123456:admin | 2 | HTTP/1.1 200 OK
20:40:23 patator INFO - 200 5223:4954 | 123456:oracle | 10 | HTTP/1.1 200 OK
20:40:26 patator INFO - 200 5223:4954 | 123456:user | 8 | HTTP/1.1 200 OK
20:40:29 patator INFO - 200 5223:4954 | 123456:adm | 6 | HTTP/1.1 200 OK
20:40:32 patator INFO - 200 5223:4954 | 123456:administrator | 9 | HTTP/1.1 200 OK
20:40:35 patator INFO - 200 5223:4954 | 123456:mysql | 7 | HTTP/1.1 200 OK
20:40:38 patator INFO - 200 5223:4954 | 12345:guest | 15 | HTTP/1.1 200 OK
20:40:41 patator INFO - 200 5223:4954 | 12345:admin | 13 | HTTP/1.1 <span clas