DVWA(Damn Vulnerable Web Application)是渗透一套故意留了坑的PHP/MySQL Web应用。它的测试唯一使命就是让你合法地把它打穿。我第一次在虚拟机上把它跑起来时,靶机浏览器弹出一个登录框,渗透默认账号admin、测试密码password,靶机输进去就进了一个灰色调的渗透界面。左侧菜单列着Brute Force、测试Command Injection、靶机SQL Injection这些选项,渗透每个模块都有一个安全等级下拉框——Low、测试Medium、靶机High、渗透Impossible。测试这套设计很直白:同一个漏洞,靶机用四种防御强度各写一遍,让你亲手感受从“完全不设防”到“理论上防住”之间的差距。
在Low级别下测试SQL Injection,输入框里敲一个
1' OR '1'='1,页面上直接吐出五个用户的名字和密码哈希。那一刻你会意识到,后端大概拼了一条SELECT * FROM users WHERE id = '$id',你的引号闭合了原语句,OR条件让WHERE永远为真。没有过滤,没有预处理,连mysql_real_escape_string都没用。切到Medium,同样的payload失效了——源码里换成了mysqli_real_escape_string,单引号被转义。但数字型注入点还在,因为开发者只给字符串参数加了转义,忘了id字段根本不需要引号。这种半吊子防御在真实代码里太常见了。Command Injection模块更有意思。Low级别下输入
127.0.0.1; whoami,页面不仅ping了本地回环,还顺带执行了whoami,返回www-data。后端大概是shell_exec('ping -c 4 ' . $ip),分号直接截断了命令。Medium级别加了黑名单,过滤了&&和;,但没过滤|。你输入127.0.0.1 | whoami,照样执行。High级别过滤更严,但如果你知道|被过滤了,试试127.0.0.1%0awhoami——换行符在某些shell解析里同样能分隔命令。Impossible级别用了escapeshellarg加白名单验证,输入必须严格匹配IP格式,这才算堵死。文件包含模块是我觉得最适合新手理解“路径穿越”的地方。Low级别下URL参数
?page=../../../../etc/passwd直接读出系统用户列表。Medium级别过滤了../和..\,但你可以用....//绕过——过滤函数删掉中间的../后,剩下的字符重新拼成../。这种“过滤一次”的逻辑漏洞在CTF里被玩烂了,DVWA把它还原得很干净。XSS模块分Reflected和Stored两种。Reflected Low级别下输入
<script>alert(1)</script>,页面直接弹窗。Stored Low级别下,你把同样的payload写进留言板,每个访问该页面的用户都会中招。Medium级别用str_replace把<script>替换成空字符串,但大小写混合<ScRiPt>就绕过了。High级别用正则preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $input),看似严格,但<img src=x onerror=alert(1)>这种非script标签的XSS照样生效。Impossible级别用了htmlspecialchars加ENT_QUOTES,这才真正把用户输入当文本处理。我建议别一上来就翻源码。先自己在Low级别下把每个模块打一遍,用Burp Suite抓包看请求和响应,猜后端逻辑。猜错了再去读源码验证。DVWA的源码不长,每个模块的PHP文件也就几十行,读起来不费劲。等你把Low到High都手动绕过一遍,再回头看Impossible的实现,会突然明白“安全编码”不是加个过滤函数就完事——它需要针对具体上下文选择正确的防御手段。SQL注入用预处理,命令执行用白名单加参数化,XSS用输出编码,文件包含用固定映射表。DVWA把这条学习曲线压进了一个不到50MB的虚拟机镜像里,这大概就是它活了十几年的原因。
顶: 3581踩: 91






评论专区