资讯动态

sqlmap实战完全指南:从基础命令到批量扫描与WAF绕过

发布时间:2026/9/15 7:50:15 来源:尧图企业网站定制
每次看到有人把sqlmap当一键脱库工具使我都觉得挺可惜的。它确实能一键跑出结果但那些只停留在会用一条 -u 命令的人一旦遇到参数加密、WAF拦截、返回包变形这类真实场景基本就卡死了。这篇文章不打算写一本sqlmap说明书而是从我这个用过几年这个工具的人的角度把sqlmap从安装、参数分层理解、批量扫描方案到真实测试中的绕过经验串一遍重点讲清楚参数背后的设计逻辑以及一套可以直接落地的批量扫描流程。适合刚开始接触SQL注入测试的Web安全工程师、CTF选手也适合那些已经会用基础命令但遇到复杂场景就无从下手的同学。1. 为什么sqlmap值得花精力学透自动化测试的真实边界我在刚入门的时候也以为SQL注入测试就是找个注入点、构造payload、提取数据三步走。结果手工测了几天进度慢不说还经常漏报。sqlmap最大的价值在于把这三步全部自动化了。它内置了数量巨大的payload库覆盖布尔盲注、时间盲注、报错注入、联合查询、堆叠查询、内联注释注入等多种注入技术可以根据目标系统的指纹自动选择最合适的检测方式。你向它丢一个URL它会自动判断注入类型、识别可用的注入参数、枚举数据库版本和当前用户权限然后进入数据提取阶段。但是要搞清楚一件事sqlmap不是万能的。市面上对它的一个典型误解是跑不出来就是没有注入。实际上sqlmap跑不出来的情况太多了常见原因包括目标存在参数加密传进去的值不是明文SQL片段、WAF对payload特征做了拦截、页面字符集导致布尔判断条件失效、请求必须携带动态token等等。这些问题的解法并不在sqlmap本身的代码里而在使用者的参数选择和辅助配置里。所以我理解的sqlmap使用水平是分层的会用基础命令-u, --dbs, -D, -T, --dump 跑通标准流程。会处理复杂请求-r 加载原始HTTP包、带cookie、带headers、POST表单。会调整检测策略--level, --risk, --technique, --tamper 精确控制payload发送方式。会做批量扫描-m 多目标、-l 加载burp日志、脚本化调度。最终级能在目标无法直接利用时手动分析流量把sqlmap和手工测试串起来。这篇博文会按从基础到进阶的顺序把这些层级的核心内容讲完。靶场环境我用DVWAlow级别和pikachu这两套来演示它们对入门练习非常友好后面也会给出搭建方式。2. 环境准备从零搭建一套可复现的sqlmap测试环境正式讲命令之前先把环境搭好。sqlmap是纯Python项目依赖pygments、requests、urllib3等库理论上只要有Python环境就能跑。这里给出两种常用安装方式我用的是源码方式因为后续要自定义tamper脚本源码在手边方便改。2.1 安装sqlmap的两种方式第一种pip安装适合快速使用。pip install sqlmap装完直接执行sqlmap就行。这种方式最大的隐藏问题是部分Linux发行版对系统Python目录有受管保护直接装会报externally-managed-environment错误。遇到这种情况优先用虚拟环境python3 -m venv sqlmap-env source sqlmap-env/bin/activate pip install sqlmap第二种git clone源码适合需要改脚本、看代码的场景。git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git cd sqlmap python sqlmap.py --version日常使用推荐第二种。一个是sqlmap更新频繁源码方式便于随时拉取最新payload库另一个是后续如果要调试自定义tamper脚本放在sqlmap目录直接引用路径比较方便。2.2 靶场搭建DVWA和pikachuDVWADamn Vulnerable Web Application搭建最省事的方式是用Dockerdocker run --rm -it -p 8080:80 vulnerables/web-dvwa浏览器访问http://127.0.0.1:8080默认账号admin/password。登录后进入DVWA Security页面把安全级别切到low。low级别下代码里基本没有任何过滤最适合观察sqlmap的各种payload如何进出参数。DVWA经典注入地址是http://127.0.0.1:8080/vulnerabilities/sqli/?id1SubmitSubmit这里有个非常容易踩的坑DVWA的注入页面需要登录session才能访问直接用-u请求会跳转登录页sqlmap会判断为目标不可达或者直接报权限问题。正确做法是先把浏览器里登录后的Cookie复制出来用--cookie参数传进去。这一点在后面命令行里会具体演示。pikachu靶场是另一套专门练手的中文靶场里面有单独的SQL注入板块区分了数字型、字符型、搜索型等场景还有sql过滤字符后手工注入这类关卡非常适合配合sqlmap学习过滤绕过。搭建方式一样可以用Docker或者本地PHP环境包里自带初始化脚本访问入口按说明走就行。2.3 验证sqlmap能否正常发请求装完后先跑一个最简单的连通性测试python sqlmap.py -u http://127.0.0.1:8080/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSID你的会话ID; securitylow --batch--batch表示所有交互提示全部使用默认值不做人工确认。这个参数在自动化脚本里极其重要后面批量扫描必须依赖它否则sqlmap每抛出一个问题都会卡住等输入。第一次跑通后sqlmap会在本地生成session文件缓存目标指纹和注入状态下一次对同一个目标测试速度会快很多。3. 核心参数的分层拆解从目标指定到数据提取别按字母序背参数我知道很多教程会按参数表一个个列但实际工作中没有人在命令行里穷举参数。更有效的思路是按测试阶段来理解参数每个阶段要解决什么问题需要哪些参数配合。我把sqlmap的参数分成五个层级。3.1 目标指定一口气说清-u、-r、-m、-l的区别这层解决的是告诉sqlmap我去测谁。参数用途典型场景-u指定单个URL简单GET请求测试-r读取原始HTTP请求文件注入点藏在POST body、特殊Header或Cookie里-m指定目标列表文件每行一个URL批量扫描后面专门展开-l加载burp或ZAP的日志文件从代理流量中自动筛选可测目标单个目标测试最常用-u注意-u的URL必须包含可测试的参数比如?id1。如果你只给一个不带参数的静态页面sqlmap会提示 unable to find any injectable parameters。-r是我个人推荐优先掌握的参数。把burp抓到的原始请求包保存成文本文件sqlmap会完整保留请求方法、URL、Headers、Body里的Cookie和各级参数避免手动复制时漏掉信息。文件内容类似GET /vulnerabilities/sqli/?id1SubmitSubmit HTTP/1.1 Host: 127.0.0.1:8080 Cookie: PHPSESSIDxxx; securitylow User-Agent: Mozilla/5.0保存后用python sqlmap.py -r dvwa-sqli-request.txt就能直接开跑。3.2 请求配置让sqlmap伪装成正常流量这部分参数解决目标认不认你的问题。真实Web系统很多都带鉴权和反爬策略直接把裸payload扔过去很容易被拒绝。常用参数--cookiePHPSESSIDxxx登录态。--user-agentMozilla/5.0...或--random-agent伪装浏览器UA。实测中很多WAF或反向代理会拦截无UA或非浏览器UA的请求所以这个参数我几乎每次都加。--headersX-Forwarded-For: 127.0.0.1\r\nReferer: http://xxx自定义Header。--delay1每次请求前等待1秒。批量测试时要特别注意目标承受能力也是降低被封概率的常规手段。--timeout10、--retries3网络较慢或代理不稳定时的兜底配置。--proxyhttp://127.0.0.1:8080挂burp把sqlmap的流量交给burp做二次观测。3.3 检测优化level、risk与technique的精确控制这是sqlmap参数体系里最核心的部分也是很多人理解最模糊的。--level控制检测深度范围是1到5。level1时默认只测试URL参数上的常见位置level越大sqlmap会测试更多注入点位置比如Cookie里的每个字段、User-Agent、Referer等HTTP头同时payload数量也会增加。默认level1时不会把Cookie和UA当作注入点这会导致一个非常常见的漏报场景注入点其实在Cookie里但你只扫了URL参数什么都没发现。所以我个人的经验是快速摸底--level1 --risk1用最小流量跑一遍全参数。细致排查--level3 --risk2覆盖大多数真实场景。危险操作--level5 --risk3会包含大量可能导致数据库写入、锁表甚至报错的payload只建议在授权测试且目标允许高负载的前提下使用。--risk的范围是0到3它控制的是payload可能产生的副作用程度。risk1的payload基本无害risk2会增加一些可能导致数据变更的语句risk3则包含基于OR、AND的全套变形这些语句在大数据量目标上可能造成严重后果。--technique可以显式指定注入技术类型。默认sqlmap会尝试所有支持的注入方式但某些场景下你需要手工过滤比如--techniqueBT # B布尔盲注T时间盲注 --techniqueE # 只测报错注入时间盲注在目标能响应但无任何回显的情况下非常有效但速度极慢一个字符一个字符地猜。利用时间盲注时--time-sec参数可以调整sleep的秒数默认是5秒。网络不好或者目标响应慢的时候--time-sec3可以明显提速但如果太短会跟正常网络延迟混淆容易误判。3.4 数据提取dbs、tables、dump的完整链路目标确认存在注入后就到了提取数据阶段。这个阶段参数相对固定核心链路是# 列出所有数据库 python sqlmap.py -u http://.../?id1 --cookie... --dbs # 切换到指定库列出表 python sqlmap.py -u http://.../?id1 --cookie... -D dvwa --tables # 指定表列出列名 python sqlmap.py -u http://.../?id1 --cookie... -D dvwa -T users --columns # 全表提取 python sqlmap.py -u http://.../?id1 --cookie... -D dvwa -T users --dump提数阶段有两个细节对结果影响很大。第一--exclude-sysdbs。不加这个参数时--dump-all会把information_schema、mysql、performance_schema等系统库全部往外拉数据量巨大、耗时长而且大多是你根本不需要的。加上--exclude-sysdbs能自动跳过系统库直接聚焦业务库。第二--batch和--dump的配合。提取大量数据时sqlmap会频繁询问是否继续测试其他参数、是否要去重之类的问题不挂--batch人会被烦死。挂上以后整体自动化程度高很多跑完直接看输出目录里的csv文件就行。3.5 利用拓展文件读写与OS Shell的姿势注入点权限允许的情况下sqlmap还能做文件读、文件写、OS Shell。这是从拿数据到进一步验证可以利用性的分水岭。# 读目标文件 python sqlmap.py -u http://.../?id1 --cookie... --file-read /etc/passwd # 写入文件到目标需知道Web绝对路径 python sqlmap.py -u http://.../?id1 --cookie... --file-write /tmp/shell.php --file-dest /var/www/html/shell.php # 尝试OS Shell python sqlmap.py -u http://.../?id1 --cookie... --os-shell--os-shell的原理是利用数据库的into outfile或into dumpfile写入一个带命令执行功能的WebShell比较依赖目标权限和写文件目录的可写权限。如果跑下来sqlmap提示无法创建文件不用死磕大概率是配置问题可以回到文件读写的思路上确认权限边界。4. 批量扫描方案的三种落地姿势与效率控制单点测试只是入门真正工作里更常见的需求是批量巡检一批URL。批量扫描的本质不是魔法而是把多个单点测试任务组织起来统一执行。这里给出三种我实际用过的批量方案。4.1 方案一-m批量目标列表最轻量把要测的URL按行写进文件http://target1.com/app/list.php?id1 http://target2.com/portal/news.php?newsid5 http://target3.com/search.php?keywordtest然后用python sqlmap.py -m urls.txt --batch --random-agent --level3 --risk2sqlmap会按行处理每个URL输出明细到终端并把每个目标的session落盘。这个方案简单直接但有个致命缺点目标间是串行执行的一个目标卡在时间盲注里后面全队都得排队。所以大规模场景下不建议单独用这个方案。4.2 方案二从burp日志自动提取目标如果你手里已经有浏览器或burp上录的真实流量这个方案最贴近真实渗透。burp的Site map里可以导出所有访问过的URL和请求sqlmap的-l参数直接支持解析burp日志XML文件。python sqlmap.py -l burp-log.xml --batch --random-agentsqlmap会从日志里识别所有带参数的请求生成候选目标列表然后逐个测试。好处显而易见流量是真实的Header、Cookie、参数位置都是原始状态不需要手动拼URL也天然解决了参数加密但请求是从浏览器发出的这类问题。4.3 方案三脚本化调度最可控如果目标数量多且质量参差我会用脚本做并发控制和时间预算管理。思路是先用请求探测一遍把响应正常且带参数的目标筛出来再交给我自己写的调度器合理分配worker数。关键点在于一个--smart和--fresh-queries的组合。--smart会在每个目标上先做轻量探测如果没有找到可注入迹象就直接跳过避免一个非注入点也跑全量payload浪费时间。--fresh-queries则强制忽略之前落盘的session缓存保证每一次测试都是真实请求而不是读取旧结果。调度脚本大概长这样import subprocess from concurrent.futures import ThreadPoolExecutor def run_sqlmap(url): cmd [ python, sqlmap.py, -u, url, --batch, --smart, --random-agent, --level3, --risk2, --exclude-sysdbs, --output-dir./result ] subprocess.run(cmd, timeout300) urls [line.strip() for line in open(candidates.txt)] with ThreadPoolExecutor(max_workers3) as ex: ex.map(run_sqlmap, urls)注意并发数必须和目标的承受能力以及你自己的出口带宽、代理能力匹配。我习惯于保持并发3到5超过这个数一方面误报明显上升一方面目标日志里可能会看到明显的扫描特征。5. 真实测试中的高频难点参数加密、WAF绕过与误报排查基础命令熟悉之后真正考验人的是各种跑不通的场景。这里把我的排查思路和经验整理出来。5.1 参数加密问题sqlmap的死穴与破解思路从热词里可以看到sql注入漏洞测试(参数加密)被反复搜索说明这是很多人实战中遇到的硬骨头。sqlmap本身不知道你的业务参数怎么加密它只能发送你给它的原始参数并观察响应变化。如果目标在后台先对参数解密再拼接SQL那么在sqlmap看来发送的payload根本不会命中数据库操作自然测不出注入。我的处理思路分三步第一步先在浏览器或burp里抓一个真实请求看原始参数值是什么样。有时加密值本身是base64有时是AES加密后的hex有时是签名参数带时间戳。搞清楚目标前端的加密算法。第二步手动调用加密函数把sqlmap要发出去的payload预加密。比如写一个中间层脚本接收sqlmap的payload加密后替换掉参数值再发送给目标。这本质上是在sqlmap和目标之间加一个适配层。第三步如果加密逻辑过于复杂或依赖前端JS代码那就放弃硬碰硬改用-r加载浏览器真实产生的带加密参数的请求去做普通参数测试或者直接用手工注入验证。sqlmap做不到的事手工payload往往能切入。5.2 WAF绕过与tamper参数另一个高频场景是目标存在WAFpayload打过去就429或403。--tamper参数就是干这个的。它本质是payload混淆器在原始payload发出之前对它做变形处理绕过基于特征匹配的WAF。常用tamper包括space2comment把空格替换成/**/能绕过一些简单空格过滤。between用BETWEEN语法替换比较运算符。securesphere对部分特征字符做重组。randomcase随机大小写绕过依赖大小写匹配的规则。equaltolike用LIKE替换。用法python sqlmap.py -u http://.../?id1 --cookie... --tamperspace2comment --random-agent多个tamper可以组合用逗号分隔--tamperspace2comment,randomcase,equaltolike需要说明的是tamper不是越多越好。每个tamper都会增加请求长度也可能引入语法错误让数据库拒绝执行。我建议逐个叠加、每加一个跑一次验证。5.3 自定义tamper脚本的编写思路如果内置tamper不够用sqlmap支持自定义tamper脚本其实就是写一个Python函数。一个最小化的自定义tamper如下#!/usr/bin/env python3 def tamper(payload, **kwargs): payload payload.replace( , /**/) payload payload.replace(, %27) return payload把文件放到sqlmap的tamper/目录命名后直接--tampermy_tamper引用。重点是理解sqlmap的调用约定每个tamper函数接收原始payload字符串返回变形后的字符串。常见自定义需求字符替换型把空格、引号、注释符替换成目标能接受的写法。编码型对payload做URL编码、双重URL编码、unicode编码。拼接型在payload前后加上合法的业务参数或注释符。5.4 误报与漏报如何验证sqlmap的结论跑批量扫描时误报是最头疼的事。sqlmap报告存在注入但人工验证半天都复现不出来。这类问题通常出在布尔盲注的判定逻辑上sqlmap通过请求后的响应内容变化来判断条件真假如果页面上存在动态内容比如时间戳、随机广告、验证码sqlmap可能把正常的内容波动误判为注入特征。解决办法是显式指定稳定的字符串。用--string参数告诉sqlmap某个字符串在条件真时一定会出现比如页面里的用户昵称或特定静态文本sqlmap就不会再依赖全页面相似度判断了。python sqlmap.py -u http://.../?id1 --cookie... --stringWelcome back admin相应地--not-string指定条件假时才出现的字符串按需调整。相反方向的漏报也很常见。页面字符集非UTF-8时sqlmap的输出解析可能不对。此时可以指定--charsetGBK或目标实际编码。另外如果目标数据库是MSSQL而你没指定--dbmsmssqlsqlmap的自动识别可能出现偏差导致payload匹配不上。所以当你能确定目标数据库类型时直接显式声明--dbmsmysql # 或者 mssql、oracle、postgresql6. 把sqlmap用在日常测试中的几点忠告工具终究是工具用得好不好取决于使用者的判断。我在实际测试中逐渐沉淀下来的几条经验分享给读到这里的你。对于任何目标的测试第一步一定是确认授权范围。sqlmap的payload库里充斥着高风险的写文件、命令执行、大数据量提取操作误操作可能造成不可逆影响。生产环境三思型使用优先在授权明确的测试环境或自建靶场里验证玩法。关于批量扫描我的建议是速度服从于质量。跑全量payload前先小流量摸底确认目标响应稳定、网络没有明显丢包再逐步加大检测等级。时间盲注场景尤其要控制并发否则慢查询可能把目标数据库拖垮。关于session缓存--flush-session是一个容易被忽略但现在我非常依赖的参数。当你修改了请求头、注入点或测试等级后如果不清理sessionsqlmap可能会直接读取缓存的旧结果导致你新参数没有真正生效。在这个地方吃过亏以后凡是重要测试我都会在脚本开头加上这句。最后一个人所用的测试思路不要完全寄生在工具自动化上。sqlmap给出的结果一定要抽时间手工复现一下关键步骤。一方面是为了确认数据真实性另一方面手工注入练习练出来的SQL理解能力是任何工具都替代不了的。我在pikachu靶场的sql过滤字符后手工注入关卡上反复练了好几次后来再回头理解sqlmap为什么选择某种payload、什么时候该切换tamper思路都清晰了很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价