某ERP系统源码审计与漏洞分析全过程记录
字数 3949 2025-09-23 19:27:46
某自研ERP系统Java源码安全审计与漏洞挖掘实战教学文档
文档说明
本文档基于安全研究人员“FyW06nIyAt”对某自研Java ERP系统的源码审计实战记录整理而成。旨在系统性地讲解该框架的特点、核心机制,并详细剖析其中存在的安全漏洞,为安全研究人员、开发人员及初学者提供一份详尽的代码审计实战指南。本文档遵循“关键点不遗漏”的原则,专注于技术细节与漏洞成因。
一、 系统与框架概览
1.1 基本特征
- 技术栈: Java Web项目。
- 数据库: 通常使用 Oracle 或 MS SQL Server。
- 鉴权方式: 基于 Session 的访问控制。
- 核心特点: 采用自研框架,其最大特色在于通过一个名为
FormService的中央Servlet,利用反射机制动态调用后端服务方法,实现前后端功能点的灵活交互。
1.2 关键指纹与鉴权方式
系统通过一个名为 PortalFilter 的过滤器对访问进行初步控制。
- 受控后缀: 对包含
.jsp,.do,.action,.ajax等特定后缀的URL请求进行拦截。 - 鉴权逻辑: 过滤器检查用户Session是否存在。若Session不存在且请求的URL包含上述受控后缀,则抛出异常并重定向到登录页面。
- 审计启示: 此鉴权仅针对明确定义的路由后缀。许多通过反射机制调用的后台功能点并未直接关联这些后缀,因此可能绕过此过滤器的基础鉴权,这是审计中需要重点关注的方向。
二、 核心机制:反射调用与鉴权 (FormService)
com.artery.form.FormService 是整个系统审计的核心入口,它本质上是一个Servlet。
2.1 核心功能
负责接收前端所有与表单相关的请求,通过解析参数,使用反射(Reflection) 动态定位并调用后端对应的Java类和方法,最终将执行结果以XML格式返回给前端。它是连接前端请求与后端业务逻辑的“中间层”或“API网关”。
2.2 调用流程与分析
- 读取配置: 从
plugins.xml等配置文件中读取服务映射关系。 - 解析服务名: 从前端传入的
service参数中解析出需要调用的服务组(Group) 和方法名(Method)。 - 反射获取方法: 通过
Class.getMethod()等方法,根据解析出的类名和方法名,获取目标Method对象。 - 参数处理: 确定目标方法的参数类型。前端数据主要通过
content参数传入,系统会根据Content-Type头(如application/xml或application/json)来解析content的内容并转换为方法所需的参数对象。 - 方法缓存: 会将反射获取到的
Method对象缓存到Map中,提升后续调用效率。
2.3 关键鉴权机制 (isAccessible)
这是审计前台漏洞的黄金法则。
- 在通过反射调用目标方法前,系统会尝试检查该方法是否定义了一个名为
isAccessible的方法。 isAccessible()方法的作用是判断当前请求是否有权限访问该功能。如果该方法返回true或存在某些允许的逻辑,则允许匿名访问。- 漏洞利用前提: 只要找到一个不存在
isAccessible方法 或者isAccessible方法逻辑存在缺陷的public方法,且该方法本身含有安全风险(Sink点),就可能实现未授权访问。
三、 漏洞详解与复现分析
以下漏洞均基于绕过 FormService 的鉴权机制进行利用。
3.1 任意文件上传漏洞
漏洞点一: com.artery.util.ServletUpload
- 漏洞方法: 该类的文件上传方法。
- 技术细节: 使用
DiskFileItemFactory处理文件上传。 - 漏洞成因: 上传文件时,会调用
bbswriteFileItem()方法,该方法继续调用bbsregisterAttachment()。在此方法中,系统为上传的文件生成一个文件名后,未对文件后缀名进行任何校验或过滤,直接将文件内容写入磁盘。 - 利用方式: 通过
FormService构造请求,调用该上传功能,上传恶意文件(如.jsp木马)。
漏洞点二: com.qy960.service.BBSService#phoneUpload
- 漏洞方法:
phoneUpload方法。 - 技术细节: 同样使用
DiskFileItemFactory。 - 漏洞成因: 与漏洞点一类似,最终也调用了未做后缀校验的
bbswriteFileItem()方法。 - 利用特点: 该方法返回的是上传后的文件名,但上传路径(
path)可能不易直接获取,需要结合其他漏洞(如目录遍历读取)或进行路径爆破。
3.2 任意文件读取/目录遍历漏洞
漏洞点: com.artery.form.services.FormStudioUpdater#getStudioFile
- 漏洞方法:
getStudioFile。 - 参数: 接收
fileStr参数,该参数直接用于文件路径拼接。 - 漏洞成因: 方法内部未对
fileStr参数中的../等序列进行过滤,导致目录遍历,可以读取服务器上的任意文件(如../../../../etc/passwd)。 - 数据传输: 由于通过
FormService调用,参数需通过content参数以特定格式(如XML)传入。 - 请求构造建议: 由于传输的是XML格式数据,将请求的
Content-Type设置为application/xml并构造相应的XML payload是最佳方式。
3.3 SQL注入漏洞 (前台)
漏洞点: com.artery.workflow.ServiceImpl#sqlResult
- 漏洞方法:
sqlResult。 - 参数: 接收外部传入的
sql参数。 - 漏洞成因: 方法内部直接将可控的
sql参数传入getFieldValue()方法中,该方法最终会执行这个SQL字符串,导致SQL注入。 - 参数构造: 传入的
params是一个JSON对象,需要在其内部嵌套一个键值对来传递恶意的SQL语句。 - 数据库差异: 原文作者提及,针对 Oracle 数据库的注入利用可能更具挑战性。
3.4 XXE漏洞 (XML外部实体注入)
漏洞点: com.artery.richclient.RichClientService#openForm
- 漏洞方法:
openForm。 - 参数: 可从外部接收一个XML格式的参数。
- 漏洞成因: 该方法没有有效的鉴权(
isAccessible缺失或为true),并且直接解析外部传入的XML数据,未禁用外部实体引用,导致XXE漏洞。 - 利用方式: 构造恶意XML内容,通过
content参数传入,可以读取服务器文件、发起内网请求等。
<!-- 示例POC结构 -->
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<content>
<someTag>&xxe;</someTag>
</content>
3.5 敏感信息泄露漏洞
漏洞点: com.artery.portal.LoginServlet
- 漏洞成因: 该Servlet在处理请求时,通过可控的
entid参数,与op参数配合触发异常后,使用getRequestDispatcher(entid).forward(request, response)进行内部转发。 - 利用方式: 通过构造特定的
entid参数(如../../WEB-INF/web.xml),可以利用内部转发机制读取Web目录下的敏感配置文件。需要确保op参数能触发异常处理流程。
四、 审计方法论总结
- 定位入口: 首先锁定系统的核心调度器
FormService,理解其反射调用和鉴权 (isAccessible) 机制。 - 寻找“无鉴权”的Public方法: 全局搜索不包含
isAccessible方法的public方法,这些是潜在的未授权访问入口。 - 数据流分析: 对找到的方法进行数据流跟踪,分析其参数是否用户可控,并最终流入危险的“Sink点”(如文件操作、数据库执行、XML解析、命令执行等)。
- 参数构造: 明确漏洞点的参数如何通过
FormService的content参数进行传递(XML或JSON格式),并正确设置Content-Type头。 - 不要忽视后台漏洞: 本文重点在于前台漏洞挖掘,但该系统同样存在大量后台SQL注入等高危漏洞,审计时不应忽略。
五、 补充与说明
- 原文作者提到还存在其他漏洞,如“任意文件压缩”等,因危害相对较低或属于后台漏洞未在本文详细展开。
- 对于文中提到的漏洞,其具体POC(Proof of Concept)因涉及敏感细节未完全公开。安全研究人员可根据描述的漏洞位置、成因和参数构造方法,自行构造验证 payload。
- 审计此类自研框架,关键在于理解其自定义的通信和鉴权机制,而非局限于传统的Spring MVC等标准框架的审计思路。
免责声明: 本文档仅用于安全技术研究和教学目的,请勿用于任何非法活动。任何个人或组织利用本文所述内容造成的任何直接或间接后果,由使用者自行承担。