
DVWA这个靶场但凡接触过Web安全的人应该都不陌生。全称是Damn Vulnerable Web Application直译过来是“该死的脆弱Web应用”专门用来给安全学习者练手。我第一次打开它的登录页时内心其实有点失望——界面极简功能朴素和真实网站比起来甚至有点简陋。但就是这么一个不起眼的本地靶场把Web渗透最经典的漏洞类型揉在了一起暴力破解、命令注入、CSRF、文件包含、文件上传、SQL注入、验证码逻辑缺陷难度还分成Low、Medium、High三级。低等级关卡不算难对新人非常友好但如果只是对着网上的Payload无脑复制粘贴通关那就太浪费了。这篇文章我会把一到七关逐关拆开从原理到实操从常用Payload到为什么要这么写全给你掰开揉碎讲清楚。适合刚搭好环境准备刷DVWA的新手也适合那些通关了但搞不懂“为什么”的回头客。1. 靶场环境搭建与预备知识1.1 为什么入门首选DVWA这类本地靶场可能有人会问学渗透测试为什么不去测真实网站真实网站涉及法律风险一个IP扫描都可能被判定为攻击行为更别说拿别人站点练手了。DVWA这一类本地靶场解决的正是这个问题——它是跑在你自己电脑上的一个模拟应用你想怎么折腾都行不用担心误伤也不用担心触线。比起同类的其他靶场DVWA最友好的地方在于“源码开源、难度分级、关卡独立”。每个功能模块单独拆开方便你对症下药地练习某一个漏洞点代码就在你手里通关之后可以直接打开看底层实现弄清一个请求为什么会被利用。这种“渗透测试加代码审计”二合一的体验是很多商业在线靶场给不了的。这里要特别说一下玩DVWA练的是测试思路和漏洞原理最终目的是为了做防护。你在心里要有一个底线——靶场里能用的手段在真实环境当中必须有授权才能使用。没有授权的探测和测试无论出于什么目的都是不被允许的。1.2 本地环境搭建实操DVWA本身是一个PHP应用跑起来需要Web服务器、PHP解释器和MySQL数据库。最简单的方案是用一个集成环境把这三个东西一次性装好省去手动配置的麻烦。具体步骤大致是安装本地集成环境内置Apache、PHP、MySQL确保相关服务能正常启动。下载DVWA源码并解压放到Web根目录下目录名保持为dvwa。找到config目录下的配置文件参考config.inc.php.dist复制一份并修改数据库连接参数默认账号密码通常对应你本地MySQL的账号密码。浏览器访问本机地址首次使用点击页面上的创建数据库按钮让DVWA自动建库建表。登录默认账号把安全等级设置为Low。整个过程10分钟就能完成。有三点容易踩坑一是端口冲突80端口容易被其他程序占用建议装好后直接在集成环境的控制面板里给Apache分配一个不常用端口二是PHP版本兼容性新版本DVWA对PHP版本有要求太老或太新的环境都可能直接白屏报错很含糊这时候优先去看PHP错误日志三是数据库初始化失败多半是config配置文件里账号密码和本地MySQL不一致改对再点初始化就行。提示DVWA一定要放在本地封闭环境里跑不要部署到任何公网环境。这个应用在设计上就是故意留漏洞的暴露在外部网络等同于把自家大门钥匙挂在门口。1.3 通关之前先养成三个习惯刷靶场之前我建议你先把自己的姿势摆对。第一每个请求发出之前都想一下“服务器凭什么允许我这样做”这会强迫你去关注请求头、Cookie、Session这些平时不在意的细节。第二打开浏览器开发者工具切到网络标签页观察每一个请求的URL、参数和响应后面很多关卡的突破口就在这个面板里。第三每通关一关立刻回去打开对应模块的源码文件把攻击Payload和代码里的漏洞做一次对照搞清楚是代码里的哪一行导致了问题。这三个习惯看起来不起眼但决定了你是“会抄作业”还是“懂原理”。Low等级的关卡网络上一搜一大把现成答案随手拷贝确实能通可一到Medium、High等级很多依赖漏洞细节的Payload就失效了。那时候能帮你的只有你对源码的理解。2. 一到三关逻辑型漏洞的入门三课2.1 第一关暴力破解暴力破解模块的页面看起来就是一个普通登录框输入用户名和密码后它会把结果直接显示在页面上这是DVWA很贴心的一个设计——你可以立刻看到尝试有没有成功。先手工试一下用户admin密码password。这个组合是DVWA的默认登录账号密码提交后页面会提示成功同时把密码显示出来。但实际练习时你不可能知道对方密码所以重点在于掌握爆破的思路。第一步用抓包工具启动代理让浏览器流量走代理然后提交一次登录请求截获请求包。Low等级下提交方式是GET用户名和密码直接暴露在URL里结构大概是login页面后面跟着username和password两个参数。拿到请求包之后在抓包工具里把它发送到爆破模块选中密码字段的值设置payload集合为一个字典文件。字典不需要很大DVWA这种练习环境准备一个1000条左右的弱口令字典足够了。开始爆破后很快就会发现字典里某一条密码会让响应长度明显区别于其他条目这条就是正确密码。为什么Low等级这么容易得手因为服务端代码里没有任何防护机制不限制尝试次数、没有验证码、没有账号锁定、也没有请求频率控制。底层逻辑就是不断地查数据库比对用户名和密码。这样做的实战意义是让你理解“缺乏速率限制”是一种常见且严重的漏洞。真实系统里的防御手段通常是三层验证码拦住自动工具、失败次数达到阈值后锁定账号、IP维度做访问频率限制。看到任何一个环节缺失你就知道系统存在被暴力破解的风险。2.2 第二关命令注入命令注入这一关做得非常直白页面要求你输入一个IP地址后台会去执行系统ping命令并把结果返回。输入127.0.0.1你会看到正常的ping回显。这时候可以试着输入127.0.0.1 whoami提交后你会发现除了ping的输出之外后面还多了一行当前操作系统的用户名。这里的关键是后台代码的执行逻辑。它把用户输入直接当成命令的一部分拼进去大概长这样把输入参数拼接到ping命令后面执行。如果你输入的只是一个IP拼接出来的命令就是ping 127.0.0.1当你输入127.0.0.1 whoami时拼接出来的命令变成ping 127.0.0.1 whoami意思是先ping一下如果成功就继续执行whoami。在Windows和Linux下、分号、管道符这些符号的作用基本相通但支持的符号有细微差别Windows下分号不能正常拼接多条命令Linux下分号可以管道符两边系统都能用。在真实测试中常见的拼接方式包括分号无论前一条命令是否成功都会执行后一条、前一条成功才执行后一条、||前一条失败才执行后一条、管道符把前一个命令的输出作为后一个命令的输入。这一关你可以在输入框里逐个试一遍感受一下不同符号带来的结果差异。这一关折射出来的问题是“命令拼接注入”——当程序需要把用户输入交给系统命令执行时如果没有白名单校验等于把系统Shell的权限向用户开放。防御手段总结起来就一句话尽量避免把用户输入直接拼到命令里如果实在要拼必须用白名单校验输入的格式并且优先使用参数化调用而不是拼好整条字符串再交给系统执行。2.3 第三关CSRF跨站请求伪造这关的页面是“修改密码”Low等级下流程非常简洁输入新密码和确认密码点击提交密码就改了全程没有验证旧密码也没有任何Token。先去抓包看看请求长什么样。你会发现修改密码的请求里只有新密码、确认密码这两个关键参数没有任何随机令牌。这意味着什么意味着服务器完全无法判断这个请求是不是用户本人主动发起的——它只认用户的会话Cookie。基于这个特性攻击者可以构造一个恶意页面。页面上放一段自动提交的JavaScript或者干脆是一个隐藏的图片标签把请求地址指向修改密码接口。当受害者访问这个恶意页面时浏览器会自动带上受害者的会话Cookie去请求那个地址于是密码被悄悄改掉。整个过程受害者毫不知情。我在本地复现这个攻击的时候是同时开启两个浏览器会话一个登录DVWA另一个打开构造好的恶意HTML文件模拟“受害者在不知情的情况下访问了一个陌生页面”的场景。结果很干脆另一个浏览器的会话密码被直接改掉。你可能觉得这种攻击需要受害者先访问恶意页面有点“被动”但放在真实场景里攻击者会把恶意请求藏在论坛帖子、邮件链接、聊天消息里配合一点社工手段成功率并不低。Low等级代码里最明显的漏洞就是修改密码请求缺少CSRF Token。CSRF的防护思路本质上就是“给敏感操作绑定一个临时随机值”服务端在表单里生成Token提交时校验TokenToken和用户的会话绑定且只能使用一次。这样即使攻击者构造了请求他也拿不到属于受害者的Token请求自然无法通过校验。配合Cookie的SameSite属性可以让浏览器在跨站请求时默认不携带Cookie又是一层保险。3. 四到五关文件类漏洞的攻防博弈3.1 第四关文件包含打开文件包含模块你会发现URL里有一个page参数看起来像这样页面路径后面接着pageinclude.php。这是典型的通过URL参数动态包含文件的写法。正常访问时它包含的是include.php这个文件。问题在于代码把page参数的值直接当作路径来用这里就要试一试能不能包含其他文件。先试最经典的在Linux系统上把page参数改成系统密码文件路径页面会直接把系统用户文件内容显示出来。这一步虽然只是“读文件”但泄露出的系统信息可能为后续攻击铺路。更高级一点可以尝试php协议伪协议读取PHP源码。这种技术特别适合用来做“代码审计”把URL改成类似pagephp过滤器和目标文件名的格式后台会把目标源码做Base64编码后输出。拿到这段编码解码之后你就可以看到服务器上这个文件的完整源码。我当时就是这么一步步把模块的底层实现捞出来的那种感觉就像把一台机器的外壳拆开终于看到齿轮是怎么咬合的一样非常过瘾。如果是远程文件包含攻击者还可以让服务器去加载一个外部恶意文件。不过远程包含对PHP配置有要求在默认配置下通常已经禁用所以练习时重点学习本地文件包含就够用了。这一关的核心防御手段是对page参数做严格的白名单校验只允许包含指定的文件同时对输入做过滤防止包含路径穿越用的../伪协议字符串再配合文件权限配置限制PHP进程可读取的文件范围。很多框架层面的文件包含漏洞本质都是“可控变量出现在文件路径里且没有被白名单约束”。3.2 第五关文件上传文件上传模块的页面是一个普通的上传表单让你提交一个文件。Low等级下服务端对上传的文件类型几乎不做任何检查文件名也不会被重命名上传后文件直接落到网站的指定上传目录并保留原文件名。我当时的操作流程是这样的先准备一个名为shell.php的文本文件内容是一句最简单的PHP代码比如phpinfo()函数调用这一步的目的是验证“上传的PHP文件能不能被服务器解析”。通过页面把它上传上去之后直接在浏览器里访问对应的目录和文件名页面如果显示出了PHP环境信息说明上传文件被当作PHP脚本执行了。接下来就是把这段验证代码换成真正的一句话木马比如一个能执行任意PHP代码的短脚本再配合一个客户端提交POST数据就能拿到一个简单的命令执行能力。不过我要强调一下这一步的乐趣不在于“拿下网站”而在于理解整个攻击链条上传入口没有校验、文件落地目录可预测、文件可以被Web服务器解析这三环缺一不可。真实环境里很多上传漏洞防御做得不够好的系统都会在这个链条上栽跟头。防御某个环节的思路很清晰一是类型校验用文件头而不是扩展名判断真实类型二是不信任用户文件名服务端重命名并随机化三是限制上传目录的解析权限让PHP文件即使传上去也不执行四是单独部署文件存储服务与Web应用隔离。做到这四点绝大部分上传漏洞就能被堵住。4. 六到七关注入与验证机制的深度拆解4.1 第六关SQL注入SQL注入是整个DVWA里最经典的一关值得你多花时间。页面是一个ID查询输入框你输入一个数字后台会去数据库里查对应ID的用户名并把结果回显在页面上。先正常输入1页面返回一个用户记录。再输入一个英文单引号1页面开始报错错误信息直接暴露了拼接后的SQL语句。这个报错很重要它告诉你两件事后台没有对输入做任何过滤查询使用的是拼接字符串的方式。这就像你拿到了一把锁的钥匙孔结构图后面的事情就好办了。Low等级实际执行的查询大概是这样的查询语句里把用户ID用一个单引号包起来我们的输入就嵌在那个引号位置。要利用这个注入点关键在于把SQL语句“闭合”回来同时把后面多余的语句“注释”掉。一个最经典的测试Payload是1 or 11拼接到语句里之后查询条件变成一个恒真的表达式结果就是整张表的数据都会返回。这一步能够验证注入是否存在。拿到注入点之后下一步是使用UNION注入读取更多数据。使用UNION有一个前提前后两个查询的列数必须一致。所以先猜列数依次提交order by 1、order by 2、order by 3如果order by 3时报错说明原查询只有2列。然后在提交union select database(), user()页面上就会显示当前数据库名和数据库用户名。再往下走可以读取表名union select table_name, table_schema from information_schema.tables这一步会把所有表名列出来找到存放用户数据的表。继续套娃把users表的密码字段读出来union select user, password from users。DVWA里存的是MD5哈希拿去在线解密就能还原出明文密码。SQL注入的根因就是“查询语句使用字符串拼接用户的输入被当成了SQL代码的一部分”。防御方案不是多写几个过滤函数而是从架构上改用预处理语句。预处理语句先让数据库编译SQL模板再把参数作为值传进去这样用户输入永远只会被当作数据不会被解析成代码。想在这一关加深理解可以打开后台源码把代码里使用拼接查询的地方和预处理写法做一次对比。我通关之后这个对比印象特别深也更确信“过滤黑名单”这类思路治标不治本。4.2 第七关不安全的验证码这一关很有意思页面还是一个修改密码的表单但多了一个验证码环节。打开页面你会发现流程分成了两步第一步填写新密码和验证码并提交第二步在确认页面上再次点击确认按钮密码才会被修改。正常走一遍流程然后用抓包工具仔细看这两步的请求。你会发现一个关键细节第一步提交新密码第二步再提交时新密码参数又出现在请求里。可以做个测试第一步随意填一个密码然后不等页面自动跳转把第二步的请求拦下来把密码参数改成完全不同的另一个值再放行。结果密码直接被改成第二步填的值整个过程中没有任何校验“第二步密码必须和第一步一致”。更致命的是第一步通过验证后服务端只是往会话里写了一个“已通过验证”的标记第二步请求只要带着这个会话过来就无条件执行改密操作。也就是说这个验证码只保护了第一步没保护第二步。攻击者可以自己完成一次第一步或者干脆想办法让会话处于已验证状态然后在第二步提交任意的目标密码。我在本地复现的时候构造了好几个不同的密码组合发现每一步都能被单独拆开来利用。这种漏洞叫“业务逻辑漏洞”它的根因不是某个具体的功能有安全缺陷而是“两个步骤之间的状态没有绑定”。验证码的通过状态和最终要修改的密码值本质上是两件独立的事情服务端却没有把它们关联起来。修复思路也不复杂第一步提交后把新密码临时存到会话里第二步不再信任用户提交的密码而是直接读取会话中存的值整个流程结束后立即清空会话状态。这样攻击者就没办法在第二步偷换密码因为密码已经“焊死”在第一步了。5. 低级关卡通关后的复盘清单5.1 七个关卡的共同规律通关之后别急着庆祝花点时间把七关的漏洞类型摆在一起看你会发现它们有一个共同点服务端没能正确区分“代码”和“数据”。SQL注入是把用户输入当成SQL代码、命令注入是把用户输入当成系统命令、CSRF是没把请求来源当成可信数据、文件上传和文件包含是让用户控制了文件的路径和类型、验证码绕过是没把两步请求当成一个整体来校验。判断一个系统是否安全本质上是在判断“哪些数据是用户可控的、这些数据最终流向了哪些敏感操作”。我把这七个关卡整理成了一张表方便你复盘时对照关卡漏洞类型根因核心防御第一关暴力破解无次数限制、无锁定机制验证码、账号锁定、频率限制第二关命令注入输入拼接进系统命令白名单校验、参数化调用第三关CSRF敏感操作无Token校验CSRF Token、SameSite属性第四关文件包含文件路径用户可控白名单、协议过滤第五关文件上传类型校验缺失、可解析类型白名单、目录防解析第六关SQL注入SQL语句字符串拼接预处理语句第七关验证码绕过流程状态未绑定状态绑定、服务端存储5.2 从“过关”到“防御”的思维升级Low等级通关只能说刚刚迈过门槛。接下来我建议你做三件事。第一把安全等级切换到Medium重新刷一遍这七关你会发现很多Low下的Payload直接失效因为你已经见过Low的源码可以尝试猜测Medium加了哪些过滤再想办法绕过。第二打开各个模块的源码做一次代码审计对着每一行代码问自己三个问题这个输入从哪来它流到哪里去中间有没有校验这个习惯练起来之后你会形成一种“漏洞直觉”。第三亲手做修复实验把Low源码里缺失的校验补上再用原来的Payload去测试体验一下防御代码是如何阻断攻击的。只有走到这一步你才算是真正理解了DVWA存在的意义——它不是让人体验“打穿网站”的快感而是让人在攻防两边反复横跳建立起完整的安全思维。5.3 常见问题速查刷DVWA的过程中我自己踩过一些坑也在不少社区帖子里看到过同类问题在这里一并做个速查整理。页面打不开或白屏优先检查PHP版本是否符合DVWA要求再检查Web服务是否正常启动端口有没有被占用。数据库初始化失败多半是config配置文件里的数据库账号密码和本地MySQL不一致确认MySQL服务在跑、账号权限足够。登录后提示CSRF Token错误通常是浏览器缓存了旧的Session清一下Cookie重新登录即可。上传PHP文件后访问没反应确认文件确实上传到了指定上传目录确认目录路径拼写正确排除被浏览器缓存的情况。命令注入在Windows和Linux结果不同这两个系统的命令分隔符支持不一样同时确认你是用哪个系统搭的环境Payload要做相应调整。用抓包工具时浏览器无法访问页面检查代理设置是否配置正确抓包工具的代理端口是否放行。这些坑大多不是技术难题而是环境问题花点时间排查一遍之后所有关卡的路就会顺畅很多。我到现在还记得第一次通关Low等级七个关卡时的感受。可能很多人会觉得这些Payload又简单又朴素没什么技术含量。但恰恰是这些“朴素”的漏洞构成了真实世界里绝大多数Web安全事件的基本盘。你越往后学越会发现高级的攻击手法往往只是基础漏洞的组合和变形。所以Low等级一定要玩得扎实不要只满足于“打进去”更要看得懂“为什么会打进去”。把这个过程走完你会真正建立起自己的安全判断力。下一步可以去挑战Medium等级了那才是真正锻炼逻辑的地方。我个人的体会是刷靶场的核心不在“量”而在“每一关多想一步”——多问一个为什么多试一种绕过方式多看一眼源码你收获的东西会完全不一样。祝通关顺利也祝你在攻防两端的思考中玩得开心。