Web App Penetration Test with DVWA
Exploit SQL injection, XSS, and command injection in a local pentest lab.
Introduction
30 Second Summary
Every time you log into a website, your data passes through code that could have security holes. Companies pay thousands of dollars to ethical hackers who find these holes before criminals do.
In this project, you will perform a real web application penetration test against a deliberately vulnerable target. You will use the same tools and methodology that professional pentesters and bug bounty hunters use daily.
What You'll Build
A complete penetration test from reconnaissance to exploitation, using Kali Linux's built-in security tools against a local vulnerable web application.
By the end of this project, you'll have:
- A portable pentest lab running DVWA inside your Kali VM, resettable with one command.
- Hands-on exploitation of three critical vulnerability classes: SQL injection, Cross-Site Scripting (XSS), and command injection.
- A repeatable penetration testing methodology you can apply to real bug bounty targets on platforms like HackerOne.
- Secret Mission: Chain multiple vulnerabilities together to escalate from initial access to full system enumeration.
Are there any prerequisites?
You need a Kali Linux VM already running in VMware. You should also have basic familiarity with Linux terminal commands and how web applications work.
Install Docker and Deploy DVWA
Every penetration test needs a target. Instead of practicing on live systems (which is illegal without authorization), you'll set up a deliberately vulnerable web application inside your own Kali VM.
Docker makes this possible with a single command. You'll install Docker, then use it to launch DVWA (Damn Vulnerable Web Application) as an isolated container that you can reset anytime.
In this step, get ready to:
- Install Docker in your Kali VM.
- Launch DVWA as a Docker container.
- Configure DVWA security level for testing.
Install Docker and verify it is running
Docker lets you run pre-built applications in isolated containers. For this project, it means launching a full vulnerable web application without manually configuring Apache, PHP, and a database.
Why Docker instead of a manual DVWA install?
Installing DVWA manually requires configuring Apache, PHP, and MariaDB separately. That's 10+ configuration steps with plenty of room for error.
Docker gives you a single command to launch the entire stack. Your goal is learning exploitation skills, not server administration.
- Open a terminal in your Kali VM by right-clicking the desktop and selecting Open Terminal Here, or clicking the terminal icon in the top taskbar.
- Update your package list and install Docker by running these commands:
sudo apt update
sudo apt install -y docker.io
Why docker.io and not docker?
In Kali Linux, there is already a package named docker (it's a system tray window manager). The Docker container engine is packaged as docker.io to avoid the naming conflict.
- Enable Docker to start automatically and start it now by running:
sudo systemctl enable docker --now
- Verify Docker is working by running:
sudo docker run hello-world
You should see a message starting with Hello from Docker! followed by a description of what Docker did to produce that output.
Don't see the Hello from Docker message?
- If you see a permission denied error, make sure you included sudo before the command.
- If you see a connection error, check that Docker is running with sudo systemctl status docker. Look for active (running) in the output.
- If the install failed, check your VM's internet connection by running ping -c 3 google.com.
Still stuck? Help me troubleshoot my Docker installation in Kali Linux
- Add your user to the Docker group by running:
sudo usermod -aG docker $USER
- Log out of your Kali session and log back in for the group change to take effect.
Why log out and back in?
Linux reads your group memberships when you log in. Adding yourself to the docker group doesn't take effect until your next session starts.
Launch the DVWA container
DVWA (Damn Vulnerable Web Application) is a PHP/MySQL web application that is intentionally full of security holes. It gives you a legal target to practice exploitation techniques.
- Open a terminal and start the DVWA container by running:
sudo docker run -d -p 80:80 --name dvwa vulnerables/web-dvwa
What does this command do?
- -d runs the container in the background (detached mode).
- -p 80:80 maps port 80 on your Kali machine to port 80 inside the container, so you can access DVWA from your browser.
- --name dvwa gives the container a memorable name for easy management.
- vulnerables/web-dvwa is the pre-built DVWA image from Docker Hub.
The first time you run this, Docker will download the DVWA image. This may take a minute depending on your internet speed.
- Open Firefox in Kali (click the Firefox icon in the top taskbar or find it in the Applications menu).
- Navigate to http://localhost in the address bar.
You should see the DVWA setup page with system information and a red button at the bottom.
- Scroll to the bottom of the page and click Create / Reset Database.
- After the database is created, you'll be redirected to the login page.
- Log in with username admin and password password.
You should now see the DVWA dashboard with a welcome message and navigation menu on the left.
Can't reach http://localhost?
- Check that the container is running with sudo docker ps. You should see the dvwa container listed.
- If the container exited, restart it with sudo docker start dvwa.
- If port 80 is in use, check for conflicts with sudo ss -tlnp | grep :80.
Still stuck? Help me troubleshoot my DVWA Docker container not loading in the browser
Configure DVWA security level
DVWA has four security levels: Low, Medium, High, and Impossible. Each level adds more protection to the vulnerabilities. You'll start on Low so you can focus on understanding each attack without dealing with filters.
- In the DVWA left-hand menu, click DVWA Security.
- In the dropdown, select Low.
- Click Submit.
The page should confirm the security level is now set to Low.
Why start on Low security?
On Low, DVWA applies zero input validation or filtering. This lets you see exactly how each vulnerability works without extra noise.
Once you understand the mechanics, you can raise the level to Medium or High and learn how to bypass common defenses.
Your pentest lab is ready. Next up, you'll use Nmap to scan your target and map its attack surface before launching any exploits.
Reconnaissance with Nmap and Nikto
You have a target running. Before exploiting anything, you need to understand what you're attacking.
Reconnaissance is the first phase of any penetration test. It maps the target's attack surface so you know exactly what software is running and where to focus your exploitation efforts.
In this step, get ready to:
- Scan the target with Nmap to discover open ports and services.
- Run Nikto to identify web-specific vulnerabilities and misconfigurations.
Run a service version scan with Nmap
Every penetration test starts with discovering what services the target exposes. Nmap probes open ports and identifies the exact software behind each one. This tells you which attack techniques are relevant.
- Run a service version scan against the DVWA container by running this command:
nmap -sV -sC localhost
What does this command do?
- -sV probes open ports to determine the service and version running on each one.
- -sC runs the default set of Nmap Scripting Engine (NSE) scripts. These perform basic checks and gather additional information about discovered services.
- localhost targets your own machine, where the DVWA container is listening on port 80.
The scan takes a few seconds. You should see output showing port 80/tcp in an open state, with the service identified as Apache httpd along with version information.
What should I see?
The output shows a table with columns for PORT, STATE, SERVICE, and VERSION. The key line confirms port 80 is open and running Apache.
Any NSE script output appears below the port entry with lines starting with |. Note the web server type and version number. This information tells you which exploits and misconfigurations to look for.
Not seeing any results?
- Make sure the DVWA container is still running. Run sudo docker ps to confirm the dvwa container is listed.
- If you see a message about the host being down, try adding -Pn to skip host discovery and scan directly.
Help me troubleshoot why Nmap isn't detecting my DVWA container on localhost.
Scan for web vulnerabilities with Nikto
Nmap told you what software is running. Now Nikto digs deeper into the web server specifically. It checks for thousands of known dangerous files, outdated components, and server misconfigurations.
- Run a Nikto scan against the DVWA web server by running this command:
nikto -h http://localhost
What does this command do?
- -h specifies the target host to scan. Since port 80 is the default for HTTP, you only need the URL.
- Nikto tests thousands of paths, files, and headers against the web server to find known vulnerabilities, default files, and misconfigurations.
The scan takes longer than Nmap because it sends many individual requests to the server. This is normal.
Wait for the scan to finish. Review the output for findings about server headers, outdated software, and interesting directories or files.
What should I see?
Nikto prints each finding as a separate line starting with +. You should see at least 3 potential issues reported.
Common findings include missing security headers, server version disclosure in HTTP headers, and accessible directories that should be restricted. Each finding is a piece of intelligence you can use during exploitation.
Nikto is not stealthy
Nikto generates a large amount of traffic and is immediately visible in server logs. In a real engagement, you would only run it against targets where you have explicit written permission to test.
Nikto seems to hang or shows errors?
- Confirm DVWA is accessible by opening http://localhost in Firefox. If the page loads, Nikto should be able to reach it too.
- If you see connection timeout errors, check that no firewall rules are blocking local traffic on port 80.
Help me figure out why Nikto cannot connect to my DVWA instance at localhost.
You now have a clear picture of your target's attack surface. You know the web server software, its version, and several potential weaknesses. Next up, you'll exploit the most dangerous one: SQL injection.
SQL Injection — Extract the Database
Your reconnaissance revealed what software the target runs and where it might be vulnerable. Now it's time to move from mapping to exploitation.
SQL injection is the most damaging vulnerability class in web applications. It happens when user input gets inserted directly into a database query without proper filtering. In this step, you'll exploit that flaw to pull the entire user database out of DVWA.
In this step, get ready to:
- Manually confirm SQL injection vulnerability in DVWA.
- Automate full database extraction using sqlmap.
- Review the extracted usernames and password hashes.
Manually test for SQL injection
DVWA's SQL Injection page takes a User ID and queries the database for it. Because the code inserts your input directly into the query string, you can manipulate the query to return data it was never meant to show.
- In Firefox, click SQL Injection in the DVWA left-side menu.
- In the User ID field, enter the following payload:
1' OR '1'='1
- Click Submit.
You should see ALL users returned on the page instead of just one. This confirms the input field is vulnerable to SQL injection.
Why does this payload work?
The application builds its database query like this: SELECT first_name, last_name FROM users WHERE user_id = '$id'. When you enter 1' OR '1'='1, the resulting query becomes WHERE user_id = '1' OR '1'='1'.
Since '1'='1' is always true, the database returns every row in the table instead of filtering to a single user.
- Now enter this more advanced payload into the User ID field to extract usernames and password hashes directly:
1' UNION SELECT user, password FROM users-- -
- Click Submit.
You should now see a list of usernames in the "First name" column and long strings of letters and numbers (MD5 hashes) in the "Surname" column.
What does UNION SELECT do here?
The UNION keyword appends results from a second query onto the original query's output. You're asking the database to also return the user and password columns from the users table.
The -- - at the end is a SQL comment that removes any remaining query syntax after your injected code, preventing syntax errors.
Not seeing any results?
Make sure the security level is set to Low. Click DVWA Security in the left menu and confirm it shows "Low" before trying again.
Check that you copied the payload exactly, including the single quotes and the space between the two dashes and the trailing dash.
Help me troubleshoot my SQL injection payload in DVWA
Automate extraction with sqlmap
Manual injection proves the vulnerability exists. Now you'll use sqlmap to automate the extraction and pull the entire user database in seconds.
- First, you need the request URL. In DVWA's SQL Injection page, enter 1 into the User ID field and click Submit.
- Look at the URL in Firefox's address bar. It should look like: http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit.
- Next, you need your session cookie. Press F12 to open Firefox DevTools.
- Click the Storage tab in DevTools.
- Expand Cookies in the left panel, then click http://localhost.
- Find the PHPSESSID cookie and copy its value.
Why does sqlmap need your cookie?
DVWA requires authentication. Without a valid session cookie, any request to the SQL Injection page gets redirected to the login screen. Passing your PHPSESSID cookie lets sqlmap act as your logged-in browser session.
- Open a new terminal tab and discover all databases by running this command:
sqlmap -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your-session-id-here;security=low" --dbs
What does this command do?
- -u specifies the target URL with the vulnerable parameter.
- --cookie passes your authenticated session cookie and the security level.
- --dbs tells sqlmap to enumerate all databases on the server.
Replace your-session-id-here with the actual PHPSESSID value you copied from Firefox DevTools.
When sqlmap asks questions during the scan, press Enter to accept the defaults. You should see a list of discovered databases including dvwa.
- Now dump the full users table from the dvwa database by running:
sqlmap -u "http://localhost/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your-session-id-here;security=low" -D dvwa -T users --dump
What does this command do?
- -D dvwa targets the dvwa database specifically.
- -T users targets the users table inside that database.
- --dump extracts all rows and columns from the specified table and displays them in a formatted table.
You should see a formatted table in your terminal showing usernames, password hashes, and other user data.
Sqlmap returning errors or redirects?
If you see messages about redirections to the login page, your PHPSESSID cookie has expired. Return to Firefox, log into DVWA again, grab the new cookie value from DevTools, and re-run the command.
Make sure you included security=low in the cookie string. Without it, DVWA defaults to a higher security level that blocks simple injection.
Help me fix my sqlmap command for DVWA
Review the extracted data
Look at the sqlmap output in your terminal. You should see a table with columns including usernames and their corresponding MD5 password hashes.
What did you just demonstrate?
A single unvalidated text field allowed you to extract the entire user database. In a real application, this would mean every user's credentials are compromised.
The sqlmap tool may have also auto-cracked some of the MD5 hashes using its built-in dictionary. MD5 is a weak hashing algorithm, and common passwords can be reversed in seconds.
You just turned a simple text field into a full database dump. Next up, you'll exploit a different vulnerability class that targets the browser instead of the database.
Cross-Site Scripting (XSS) — Cookie Theft
SQL injection targets the server's database. Cross-Site Scripting (XSS) targets other users' browsers.
When a web application reflects user input back to the page without sanitizing it, an attacker can inject JavaScript that runs inside the victim's browser. This lets them steal session cookies, hijack accounts, or rewrite what the page displays. You will now prove this vulnerability exists in DVWA by injecting script tags and reading the session cookie.
In this step, get ready to:
- Exploit reflected XSS to execute JavaScript in the browser.
- Demonstrate how XSS can steal session cookies.
- Test stored XSS to confirm the payload persists for all users.
Test for reflected XSS
Reflected XSS happens when user input is immediately echoed back into the page without any filtering. If you can inject a script tag and see it execute, the application is vulnerable.
- In DVWA, click XSS (Reflected) in the left navigation menu.
- You will see a form asking "What's your name?" with a text input field.
- Enter the following payload into the text field:
<script>alert('XSS')</script>
- Click Submit.
What does this payload do?
The <script> tag tells the browser to execute the JavaScript inside it. alert('XSS') pops up a dialog box with the text "XSS".
If the application properly sanitized input, the browser would display the literal text <script>alert('XSS')</script> on the page instead of executing it. The alert box popping up proves the input ran as code.
An alert box should pop up in your browser displaying the text "XSS". This confirms the application does not sanitize the input before reflecting it back.
- Click OK to dismiss the alert box.
No alert box appeared?
- Make sure your DVWA security level is set to Low. Higher security levels filter script tags.
- Check that you typed the payload exactly, including the single quotes around 'XSS'.
- Confirm you are on the XSS (Reflected) page, not one of the other XSS variants.
Why isn't my XSS alert appearing in DVWA?
Steal the session cookie
An alert box proves code execution, but a real attacker wants data. The most valuable target is the session cookie, because stealing it lets an attacker impersonate the logged-in user without knowing their password.
- On the same XSS (Reflected) page, enter this payload into the text field:
<script>alert(document.cookie)</script>
- Click Submit.
What does document.cookie reveal?
The JavaScript object document.cookie returns all cookies accessible to the current page. In DVWA, this includes your PHPSESSID (your session identifier) and the security cookie (the DVWA difficulty level).
In a real attack, an attacker would send this cookie value to a server they control instead of displaying it in an alert. With the PHPSESSID, they could paste it into their own browser and instantly take over the victim's session.
The alert box should now display your cookie values, showing something like PHPSESSID=abc123; security=low.
- Click OK to dismiss the alert.
Now test the stored variant to see how XSS can persist and affect every visitor to a page.
- In the left navigation menu, click XSS (Stored).
- You will see a guestbook form with Name and Message fields.
- Enter any name in the Name field (for example, test).
- Enter the following payload in the Message field:
<script>alert(document.cookie)</script>
- Click Sign Guestbook.
Why is stored XSS more dangerous?
Reflected XSS requires tricking a victim into clicking a crafted link. Stored XSS saves the malicious payload in the application's database. Every user who views the guestbook page triggers the script automatically, with no social engineering required.
This makes stored XSS far more impactful in a real engagement. One injection can compromise every user who visits the page.
The alert box should pop up again showing your cookie values. This payload is now saved in the guestbook. Every time any user loads this page, the script executes and exposes their session cookie.
Stored XSS not executing?
- Make sure you entered the payload in the Message field, not the Name field. The Name field has a character limit that may truncate your payload.
- Confirm the security level is still set to Low. Navigate to DVWA Security in the left menu to verify.
Why is my stored XSS payload not working in DVWA?
You have proven that DVWA's input fields are completely unprotected against script injection. Next up, you will exploit command injection to run operating system commands directly on the server.
Command Injection — Execute System Commands
You have extracted a full database via SQL injection and stolen session cookies through XSS. Now it is time for the most dangerous vulnerability class in web application security: command injection.
Command injection lets an attacker run operating system commands directly on the server through a web form. A single vulnerable input field can give an attacker the same access as if they were sitting at the server's terminal.
In this step, get ready to:
- Exploit command injection to run operating system commands on the server.
- Enumerate the system to demonstrate the severity of this vulnerability.
Test basic command injection
DVWA's Command Injection page has an input field that asks you to enter an IP address to ping. Behind the scenes, the server passes your input directly into a system command without any sanitization.
- In DVWA, click Command Injection in the left menu.
- You will see a text field asking you to enter an IP address to ping.
- In the input field, type the following payload:
127.0.0.1; whoami
- Click Submit.
What does this payload do?
The semicolon (;) terminates the ping command that the server intended to run. Everything after it executes as a separate command on the operating system.
So the server actually runs: ping -c 4 127.0.0.1; whoami. The ping runs normally, then whoami executes and prints which user the web server runs as.
You should see the normal ping output followed by www-data at the bottom. This confirms that you are executing commands as the web server's user account.
Not seeing any output?
Make sure you typed the semicolon (;) and not a colon (:). The semicolon is the shell operator that separates commands.
Confirm your DVWA security level is still set to Low by checking the footer of any DVWA page. Higher security levels filter the semicolon character.
Help me troubleshoot why my command injection payload isn't producing output in DVWA.
Enumerate the system through command injection
A single whoami confirms the vulnerability exists. Now you will run additional commands to show how much damage an attacker can do with this access.
- Return to the Command Injection input field and enter the following payload to list all system users:
127.0.0.1; cat /etc/passwd
- Click Submit.
You should see the full contents of /etc/passwd displayed on the page. This file lists every user account on the Linux system.
- Now enter this payload to reveal the kernel version:
127.0.0.1; uname -a
- Click Submit.
The output shows the full kernel version and system architecture. An attacker uses this to find kernel exploits that could escalate privileges.
- Enter one more payload to list the root filesystem:
127.0.0.1; ls /
- Click Submit.
You should see a directory listing of the server's root filesystem, including folders like bin, etc, home, and var.
Why is this so dangerous?
Each of these commands demonstrates that the attacker has direct access to the underlying operating system. Reading /etc/passwd reveals user accounts. Checking the kernel version enables privilege escalation research. Listing directories helps the attacker find sensitive files, config files, or credentials.
In a real engagement, command injection is often considered "game over" because the attacker can read files, install backdoors, or pivot to other systems on the network.
Seeing only ping output?
If you see the ping results but no command output below them, check that you are using a semicolon (;) and not a pipe (|). Both work at Low security, but the semicolon produces the clearest output.
If the page just refreshes with no output at all, the container may have an issue. Restart it by running sudo docker restart dvwa in your terminal, then try again.
Help me figure out why my command injection enumeration payloads aren't producing results.
Understand the impact of command injection
You have just demonstrated that a web form intended only to ping an IP address can be abused to run arbitrary commands on the server. The application trusted user input and passed it directly to a system shell.
How does this compare to SQL injection and XSS?
SQL injection targets the database layer. XSS targets the browser of other users. Command injection targets the server's operating system itself.
Of the three, command injection typically has the highest severity because it gives the attacker direct shell access. From here, an attacker can read any file the web server user has access to, install persistent backdoors, or use the compromised server as a launchpad to attack internal systems.
You have now exploited all three major vulnerability classes. Up next in the Secret Mission, you will chain these vulnerabilities together to simulate how a real attacker escalates from initial access to full system enumeration.
Secret mission
Vulnerability Chaining
In a real penetration test, individual vulnerabilities rarely matter in isolation. Attackers chain findings together to escalate access and maximize impact. Your mission: combine SQL injection, password cracking, and command injection into a single attack path that moves from initial database access to full configuration file exfiltration.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally in your Kali VM, so there are no ongoing costs.
Resources you used:
- Docker container dvwa running on port 80.
- Docker image vulnerables/web-dvwa stored locally.
- Local file hashfile.txt containing the extracted MD5 hash.
Keep everything running
No action needed. Choose this if you are still actively practicing exploitation techniques or want to try DVWA at higher security levels.
- Your DVWA container auto-starts with Docker whenever your Kali VM boots.
- Access it anytime at http://localhost in Firefox.
- Try increasing the security level to Medium or High to practice bypassing stronger defenses.
Pause - I'll come back to this later
Shut down the DVWA container to free up memory while keeping everything ready to restart later.
- Stop the DVWA container by running:
sudo docker stop dvwa
- When you are ready to practice again, restart it by running:
sudo docker start dvwa
- Then navigate to http://localhost in Firefox to pick up where you left off.
Delete - I don't want to use this again
Remove all project resources completely to reclaim disk space and start fresh.
- Remove the DVWA container by running:
sudo docker rm -f dvwa
- Remove the DVWA Docker image to reclaim disk space by running:
sudo docker rmi vulnerables/web-dvwa
- Delete the local hash file by running:
rm hashfile.txt
- Docker itself remains installed for future projects. If you want to remove Docker entirely, run:
sudo apt remove -y docker.io
What about John the Ripper's cracked passwords?
John the Ripper stores cracked passwords in its local pot file. These are from a practice lab, so they pose no security risk. They are cleared automatically if you ever reinstall John.
Nice Work!
Nice Work!
You just completed a full web application penetration test from reconnaissance through exploitation. You deployed a target, mapped its attack surface, and exploited three of the most critical vulnerability classes in web security.
Here's what you accomplished:
- Exploited SQL injection both manually and with sqlmap to extract an entire user database including usernames and password hashes.
- Demonstrated cookie theft via XSS to show how attackers hijack user sessions through unsanitized input.
- Executed operating system commands through command injection on the web server, reading system files like /etc/passwd directly from a web form.
- Secret Mission: Chained vulnerabilities together (SQLi to credential cracking to lateral movement to data exfiltration) like a professional penetration tester.
Ready to quiz yourself?