Hack Your First Web App with DVWA
Exploit SQL injection and command injection in a local pentesting lab.
Introduction
30 Second Summary
Every week, another company makes headlines for a data breach. Understanding how attackers find and exploit vulnerabilities is the foundation of defending against them.
In this project, you will hack a deliberately vulnerable web application using the same techniques real penetration testers use. You will set up DVWA (Damn Vulnerable Web Application) in a safe, local lab and work through each stage of the attack.
What You'll Build
A complete penetration test against DVWA, covering reconnaissance, exploitation, and credential extraction.
By the end of this project, you'll have:
- A running pentesting lab using Docker and DVWA, ready for ongoing practice.
- Nmap scan results showing discovered services and versions on your target.
- Extracted database credentials via SQL injection, both manually and with sqlmap.
- Secret Mission: Crack password hashes using John the Ripper, completing the full attack chain from discovery to credential compromise.
Are there any prerequisites?
This project assumes you are running Parrot OS Security Edition, which comes with all required tools pre-installed.
You should be comfortable with basic networking concepts (ports, IP addresses, HTTP) and navigating the Linux terminal.
Set Up Your Hacking Lab
Every penetration test starts in a controlled lab. Real pentesters never attack live systems without written permission. Instead, they build isolated environments with intentionally vulnerable targets that simulate real-world flaws.
In this step, you will confirm your security tools are ready, spin up a vulnerable web application inside a Docker container, and configure it for testing.
In this step, get ready to:
- Confirm Nmap, sqlmap, and John the Ripper are installed and working.
- Launch DVWA and its database in Docker containers.
- Log in to DVWA and set the security level to Low.
Verify your pre-installed tools
Parrot OS Security Edition ships with over 800 security tools pre-installed. Before jumping into the project, let's confirm the three you will need are ready to go.
- Open a terminal by pressing Alt+T on your keyboard.
- Check that Nmap is installed by running:
nmap --version
You should see a version number and build details printed in your terminal.
- Check that sqlmap is installed by running:
sqlmap --version
You should see a version string confirming sqlmap is available.
- Check that John the Ripper is installed by running:
john --help
You should see usage information listing John the Ripper's available options and flags.
Seeing 'command not found'?
Make sure you are running Parrot OS Security Edition, not the Home Edition. The Security Edition includes all penetration testing tools via the parrot-tools-full metapackage.
Help me install a missing security tool on Parrot OS.
Clone and launch DVWA with Docker
Now you need a target to hack. DVWA (Damn Vulnerable Web Application) is a PHP web app that is intentionally riddled with security holes. You will run it inside Docker so it stays completely isolated from the rest of your system.
- Clone the official DVWA repository to your home directory by running:
cd ~
git clone https://github.com/digininja/DVWA.git
You should see download progress followed by a confirmation that the clone is complete.
Clone failing?
Make sure you have an active internet connection. If you see a permission error, check that git is installed by running git --version.
Help me troubleshoot cloning the DVWA repository on Parrot OS.
- Move into the DVWA folder and start the containers by running:
cd DVWA
docker compose up -d
What does this do?
docker compose up -d reads the compose.yml file inside the DVWA repository and spins up two containers. One runs the DVWA web app itself. The other runs a MariaDB database to store user accounts and vulnerability data.
The -d flag runs the containers in the background so you can keep using your terminal.
First run takes longer
Docker needs to download the DVWA and MariaDB images the first time you run this command. This may take a minute or two depending on your internet speed.
- Confirm both containers are running by running:
docker compose ps
You should see two containers listed: dvwa and db. Both should show a running status.
Containers not running?
Make sure the Docker service is active on your machine. If you see an error about Docker not being reachable, start the Docker service first, then run docker compose up -d again from inside the DVWA folder.
If only one container appears, wait 30 seconds and run docker compose ps again. The database container sometimes takes a moment to initialize.
Help me troubleshoot Docker containers not starting on Parrot OS.
Log in and configure DVWA
With the containers running, DVWA is now live on your machine. You need to initialize its database and lower its security defenses so you can practice attacks against it.
- In your web browser, navigate to http://localhost:4280.
- Enter admin in the Username field.
- Enter password in the Password field.
- Click Login.
You should see the DVWA setup page with a Database Setup section and a system information checklist.
- Scroll to the bottom of the setup page.
- Click Create / Reset Database.
What does Create / Reset Database do?
This populates the MariaDB database with the default user accounts, password hashes, and vulnerability data that DVWA's modules rely on. Without this step, the attack modules have nothing to work with.
After the database is created, DVWA redirects you back to the login page. This is expected.
- Log in again with username admin and password password.
- Click DVWA Security in the left-hand menu.
- Select Low from the security level dropdown.
- Click Submit.
You should see a confirmation message that the security level has been set to low.
What are DVWA security levels?
DVWA has four security levels: Low, Medium, High, and Impossible. Each level adds more defenses against attacks, like input validation and parameterized queries.
Starting at Low means the application has no security measures at all. This lets you focus on understanding how the attacks work before facing any countermeasures.
Page not loading at localhost:4280?
Switch back to your terminal and run docker compose ps from inside the DVWA folder. Both the dvwa and db containers must show a running status.
If the containers are running but the page still won't load, wait 30 seconds and refresh. The web server sometimes needs a moment to start up after the containers launch.
Help me access DVWA in my browser on Parrot OS.
Your hacking lab is live and ready. Next up, you will scan your target with Nmap to discover what services it exposes.
Reconnaissance with Nmap
Your hacking lab is up and running. Before you start attacking, you need to know exactly what's running on your target.
This is where reconnaissance comes in. Nmap is the go-to network scanning tool in cybersecurity, used to discover open ports, running services, and software versions on a target.
In this step, get ready to:
- Scan your DVWA target with Nmap to discover running services and versions.
- Compare basic and aggressive scan results to understand what each reveals.
- Interpret your findings to map the attack surface.
Run a service version detection scan
Nmap's -sV flag probes open ports to figure out what software is responding and what version it is running. Knowing the exact service and version is the first step toward finding known vulnerabilities.
- Scan port 4280 on your DVWA target by running this command:
nmap -sV -p 4280 127.0.0.1
What does this command do?
- -sV probes the open port to determine the service and version running on it.
- -p 4280 tells Nmap to only scan port 4280, where your DVWA container is listening.
- 127.0.0.1 is the target IP address. Since DVWA runs locally in Docker, you scan localhost.
- Look at the output table. You should see port 4280/tcp listed with a STATE of open.
- Check the SERVICE column. It should show http. The VERSION column should show Apache httpd with a version number.
Not seeing port 4280 as open?
- Your DVWA containers might have stopped. Check their status by running:
docker compose ps
- If the containers have stopped, bring them back by running:
docker compose start
Nmap isn't detecting my DVWA service on port 4280. Help me troubleshoot.
Run an aggressive scan
The basic version scan told you what service is running. An aggressive scan goes further, pulling OS details, running Nmap's built-in scripts, and tracing the network path to the target.
- Run a more comprehensive scan by running this command:
nmap -A -p 4280 127.0.0.1
What does the -A flag do?
The -A flag enables OS detection, version detection, script scanning, and traceroute all at once. It is Nmap's "kitchen sink" option for getting as much information as possible about a target.
Script scanning runs Nmap's built-in NSE scripts, which probe for common configurations and known issues. This is how Nmap discovers things like HTTP page titles and server headers that a simple version scan would miss.
- Compare this output to your first scan. You should see additional information including HTTP page titles, server headers, and script scan results.
Scan taking a long time?
- The -A flag runs more probes than -sV, so it takes longer. Give it up to 60 seconds to complete.
- If it hangs for more than a few minutes, press Ctrl+C to cancel and try running it again.
My aggressive Nmap scan is hanging or not completing. Help me troubleshoot.
Interpret your results like a pentester
In a real penetration test, reconnaissance is where you map the attack surface before touching anything. Every detail in your scan output matters.
- Review your scan output and identify these key findings:
- What service is running on port 4280? What exact version did Nmap detect?
- What operating system details were revealed by the aggressive scan?
- What does this information tell you about potential attack vectors?
Why does reconnaissance matter?
Knowing the exact web server software and version lets you search for known vulnerabilities specific to that version. Knowing the OS helps you predict what tools and commands are available if you gain access.
On a real engagement, pentesters document every finding from this phase. The more you know about the target, the more precisely you can plan your exploitation.
You now know what's running on your target. In the next step, you'll use that knowledge to exploit a SQL injection vulnerability and extract real credentials from the database.
Exploit SQL Injection
Your Nmap scans revealed the services running on your target. Now it's time to use that information to find and exploit an actual vulnerability.
SQL injection works by inserting malicious SQL code into input fields, tricking the database into executing unintended queries. In this step, you'll exploit this vulnerability in DVWA to extract real credentials from the database.
In this step, get ready to:
- Confirm a SQL injection vulnerability by manipulating a database query.
- Extract usernames and password hashes from the database.
- Automate the full attack using sqlmap.
Confirm the SQL injection vulnerability
DVWA has a module specifically designed to teach SQL injection. You'll start by sending normal input to see how the application behaves, then inject a payload that breaks the intended query.
- Click SQL Injection in DVWA's left-hand menu.
- Enter 1 in the User ID field.
- Click Submit.
The application returns a single user record. This tells you the form queries the database based on whatever you type into the input field.
- Enter this payload into the User ID field and click Submit:
' OR '1'='1
What does this payload do?
The single quote at the start closes the original SQL string that the application built around your input. The OR '1'='1' part adds a condition that is always true.
This tricks the database into returning every row in the table instead of just one. You've just confirmed the vulnerability manually.
You should now see multiple user records displayed on the page instead of just one.
Only seeing one record?
- Make sure you copied the payload exactly, including the single quotes. Even one missing quote changes how the database interprets the input.
- Check that your DVWA security level is still set to Low. Higher levels add input filtering that blocks this payload.
- Why isn't my SQL injection payload returning all the records in DVWA?
Extract credentials with a UNION-based injection
Confirming the vulnerability is just the first step. A real attacker would escalate by pulling sensitive data out of the database. UNION-based injection lets you attach a second query to the original one, targeting any table you want.
- Enter this payload into the User ID field and click Submit:
%' and 1=0 union select null, concat(user,':',password) from users #
What does this payload do?
- %' and 1=0 closes the original query and forces it to return zero rows, so only your injected results appear.
- union select null, concat(user,':',password) from users appends a second query that pulls every username and password hash from the users table, joined with a colon.
- The # at the end comments out any remaining SQL that the application would have added after your input.
You should see a list of usernames paired with long strings of letters and numbers. Those strings are MD5 password hashes stored in the database.
- Record the usernames and hashes you see in the results. You'll need them later.
Seeing an error or no results?
- Double check that you copied the payload exactly. The %' at the start and # at the end are both essential.
- Confirm you are on the SQL Injection page, not the SQL Injection (Blind) page. Blind injection returns different output.
- Why isn't my UNION-based SQL injection returning usernames and hashes?
Automate the attack with sqlmap
Manual injection is great for understanding the vulnerability, but real pentesters also use automated tools to speed up the process. sqlmap is a tool that detects and exploits SQL injection flaws automatically.
Before you can run sqlmap, you need to grab your session cookie from the browser. Without it, DVWA redirects requests to the login page instead of the vulnerable form.
- Return to your browser with DVWA open.
- Press F12 to open Developer Tools.
- Click the Storage tab.
- Expand Cookies in the left sidebar and click http://localhost:4280.
- Find the PHPSESSID row and copy its Value. Keep this value handy for the next two commands.
Why does sqlmap need your session cookie?
sqlmap sends HTTP requests to DVWA on your behalf. DVWA requires a logged-in session to access the vulnerability modules. Without the PHPSESSID cookie, every request gets redirected to the login page.
- Switch back to your terminal. Enumerate all databases on the server by running this command, replacing your-session-id with the PHPSESSID value you just copied:
sqlmap -u "http://localhost:4280/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your-session-id;security=low" --dbs --batch
What does this command do?
- -u points sqlmap at the vulnerable URL, including the id parameter it will test for injection.
- --cookie attaches your session cookie so DVWA treats the requests as authenticated.
- --dbs tells sqlmap to enumerate all databases on the server.
- --batch runs the tool non-interactively, accepting default answers for any prompts.
sqlmap will test various injection techniques and then list the databases it found. You should see dvwa and information_schema in the output.
sqlmap not finding the injection?
- Make sure you replaced your-session-id with your actual PHPSESSID value. An invalid session causes DVWA to redirect to the login page.
- Confirm your DVWA containers are still running by running docker compose ps in the DVWA directory.
- Why is sqlmap not detecting the SQL injection vulnerability in DVWA?
- Dump the users table from the dvwa database by running this command, again replacing your-session-id with your PHPSESSID value:
sqlmap -u "http://localhost:4280/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your-session-id;security=low" -D dvwa -T users --dump --batch
What changed in this command?
- -D dvwa targets the dvwa database you discovered in the previous scan.
- -T users narrows the dump to just the users table.
- --dump tells sqlmap to extract all rows from that table and display them.
You should see a formatted table with usernames and their MD5 password hashes. Compare these results with what you extracted manually. The data should match.
Why use both manual and automated techniques?
Manual injection proves you understand how the vulnerability works. Automated tools like sqlmap speed up the extraction process and can discover injection points you might miss by hand.
Professional pentesters use both. Manual testing demonstrates skill and understanding, while automation ensures thorough coverage.
sqlmap dump returning empty results?
- Check that you typed -D dvwa and -T users exactly. Database and table names are case-sensitive.
- If your session expired, go back to DVWA in your browser, refresh the page, and copy a fresh PHPSESSID from the Storage tab.
- Why is my sqlmap dump not showing any data from the DVWA users table?
You've pulled credentials straight out of the database using both manual and automated techniques. Next up, you'll take control of the server itself by exploiting command injection.
Exploit Command Injection
In the last step, you exploited SQL injection to extract usernames and password hashes from the database. Now you'll target an even more dangerous class of vulnerability.
Command injection lets an attacker run operating system commands directly on a web server. Instead of manipulating database queries, you'll trick the application into executing system-level commands on the machine itself.
In this step, get ready to:
- Test the DVWA command injection module with normal input to understand how it works.
- Exploit command injection to read sensitive server files.
- Gather system information to map out post-exploitation opportunities.
Test the command injection module with normal input
The Command Injection module in DVWA simulates a web form that takes an IP address and runs the operating system's ping command against it. When an application passes user input directly to a system command without sanitizing it, attackers can append their own commands.
- In the DVWA left-hand menu, click Command Injection.
- Enter 127.0.0.1 in the input field.
- Click Submit.
You should see normal ping output showing replies from 127.0.0.1. This confirms the form is working and passes your input to the system's ping command.
Why start with normal input?
Testing with expected input first shows you what the application does under normal conditions. Once you know what normal output looks like, any extra output tells you your injection worked.
Not seeing any output?
- Make sure the DVWA containers are still running. Switch to your terminal and run docker compose ps from the DVWA directory to check.
- Check that the security level is set to Low by clicking DVWA Security in the left-hand menu.
Why isn't the DVWA command injection module showing any output?
Inject a command to read the server's password file
Now that you know what normal output looks like, it's time to inject your own command. The semicolon character tells the operating system to treat everything after it as a separate command.
- Clear the input field.
- Enter 127.0.0.1; cat /etc/passwd in the input field.
- Click Submit.
You should see the ping output followed by the contents of the /etc/passwd file. That second block of output is the proof that your injection worked.
What just happened?
The application constructed a system command like ping 127.0.0.1; cat /etc/passwd. The semicolon told the operating system to run cat /etc/passwd as a completely separate command after ping finished.
This is remote code execution through a web application. It's one of the most critical vulnerabilities in the OWASP Top 10 because it gives an attacker direct access to the server's operating system.
Only seeing ping output?
- Double-check that you included the semicolon before cat. Without it, the entire payload is treated as part of the IP address and the ping command fails silently.
- Verify the security level is set to Low. Higher security levels add input filtering that blocks this payload.
Why is my command injection payload only showing ping output in DVWA?
Discover the server's identity and operating system
In a real penetration test, confirming command execution is just the start. The next step is gathering information about the server to plan your post-exploitation strategy.
- Clear the input field.
- Enter 127.0.0.1; whoami in the input field.
- Click Submit.
The output reveals the username that the web server process runs as. This tells you what level of privileges your injected commands have on the system.
- Clear the input field.
- Enter 127.0.0.1; uname -a in the input field.
- Click Submit.
The output shows the operating system and kernel version running on the server. In a real engagement, this helps determine what privilege escalation exploits and lateral movement techniques are available.
What is post-exploitation?
Post-exploitation is everything that happens after gaining initial access to a system. It includes privilege escalation (getting root access), lateral movement (spreading to other systems), and persistence (maintaining access after reboots).
The whoami and uname -a outputs are the first pieces of that puzzle. They tell a pentester what access level they have and what exploits might work on the target system.
Secret mission
Crack the Password Hashes
You've extracted usernames and password hashes from the database. But hashes aren't passwords. Can you turn them into plaintext credentials and complete the full attack chain from reconnaissance to credential compromise?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on your machine, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Two Docker containers (dvwa web app and db MariaDB database).
- One Docker volume (dvwa) storing the MariaDB data.
- One Docker network (dvwa) connecting the two containers.
- The cloned DVWA directory on your machine, including hashes.txt from the Secret Mission.
Keep everything running
No action needed. Choose this if you want to keep practicing with DVWA's other vulnerability modules.
Both containers are configured with restart: unless-stopped, so DVWA stays available at http://localhost:4280 even after you reboot your machine.
DVWA has several more modules to explore beyond SQL injection and command injection. Try XSS, CSRF, File Upload, and Brute Force to keep building your offensive security skills.
Pause - I'll come back to this later
Shut down running containers to free up memory, but keep everything in place so you can pick up where you left off.
- Make sure you are in the DVWA directory, then stop the containers by running:
docker compose stop
- When you are ready to resume, navigate back to the DVWA directory and restart the containers by running:
docker compose start
Your database, volume, and network all remain intact. DVWA will be available again at http://localhost:4280 once the containers finish starting.
Delete - I don't want to use this again
Remove all project resources and start fresh. This is permanent and cannot be undone.
- Make sure you are in the DVWA directory, then remove the containers, network, and database volume by running:
docker compose down -v
- Remove the Docker images to reclaim disk space by running these commands:
docker image rm ghcr.io/digininja/dvwa:latest
docker image rm mariadb:10
- Move out of the DVWA directory and delete it by running:
cd ~
rm -rf DVWA
This removes the cloned repository, hashes.txt, and all other project files. Everything from this project is now cleaned up.
That's a Wrap!
That's a Wrap!
Nice work! You just completed a full penetration test against a live web application, following the same methodology real security professionals use on paid engagements.
You've learned how to:
- Set up a fully isolated pentesting lab using Docker and DVWA, a real training platform used by security professionals worldwide.
- Performed network reconnaissance with Nmap, identifying services and versions running on your target.
- Exploited real web application vulnerabilities (SQL injection and command injection) to extract database credentials and execute OS commands through a web application.
- Secret Mission: Cracked extracted MD5 password hashes using John the Ripper, completing the full attack chain from discovery to credential compromise.
Ready to quiz yourself?