目录
0x00 前言
0x01 鉴权方式&审计思路
1、目前主流的鉴权方式
2、鉴权漏洞审计思路
0x02 Interceptor鉴权审计 - NewbeeMall电商系统
1、项目介绍 - NewbeeMall
2、Interceptor 补充介绍
3、NewbeeMall - Interceptor鉴权 - 代码审计
0x03 Filter鉴权审计 - 华夏ERP进销存系统
1、项目介绍 - 华夏ERP
2、华夏ERP - Filter - 代码审计
0x04 Shiro鉴权审计 - Tumo博客系统
1、项目介绍 - Tumo博客系统
2、Tumo - Shiro - 代码审计
0x05 JWT鉴权审计 - FastCMS
1、项目介绍 - FastCMS
2、JWT鉴权漏洞审计思路
3、FastCMS - JWT - 代码审计
0x00 前言
希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢!
个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog
0x01 鉴权方式&审计思路
1、目前主流的鉴权方式
Interceptor是一种拦截器,也称之为拦截器链(Interceptor Chain),主要用于拦截请求、响应或处理过程中的某些事件,比如权限认证、日志记录、性能测试等。在 Java 中,Interceptor可以用来扩展框架,增加或修改某个方法的行为,或者对应用流程做些前置处理、后置处理、环绕处理等。
Filter被称为过滤器,过滤器实际上就是对Web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用filter技术,可以实现对所有Web资源的管理,例如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
JWT(JSON Web Token),将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。这使得JWT成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
2、鉴权漏洞审计思路
不同于常规审计思路,鉴权漏洞几乎没有业务关键词供搜索,其特征较弱。所以,针对鉴权漏洞的代码审计,思路为直接找鉴权技术特征目录进行代码追溯。
-
找有没有 Interceptor ,拦截器里有没有鉴权
-
找有没有 Filter ,过滤器里有没有鉴权
-
找有没有 Shiro ,看版本及里面的逻辑配置
-
找有没有 JWT ,看后面写的四个方向确定
-
若以上都没有,可能是自写的鉴权代码
0x02 Interceptor鉴权审计 - NewbeeMall电商系统
1、项目介绍 - NewbeeMall
Newbee-mall 项目是一套电商系统,包括 newbee-mall 商城系统及 newbee-mall-admin 商城后台管理系统,基于 Spring Boot 2.X 及相关技术栈开发。
前台商城系统包含首页门户、商品分类、新品上线、首页轮播、商品推荐、商品搜索、商品展示、购物车、订单结算、订单流程、个人订单管理、会员中心、帮助中心等模块。
后台管理系统包含数据面板、轮播图管理、商品管理、订单管理、会员管理、分类管理、设置等模块。
下载:https://github.com/newbee-ltd/newbee-mall
2、Interceptor 补充介绍
参考:Spring Boot拦截器(Interceptor)详解
Interceptor必须重写以下三个方法:preHandle、postHandle、afterCompletion
- preHandle 方法:在请求处理之前被调用。当它返回 false 时,表示拦截请求,不继续执行后续处理器;当它返回为 true 时,表示放行请求,继续执行后续处理器
- postHandle 方法:在 Controller 方法调用之后执行
- afterCompletion 方法:在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行
public class LogInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("\n-------- LogInterception.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Start Time: " + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- LogInterception.postHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("\n-------- LogInterception.afterCompletion --- ");
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("End Time: " + endTime);
System.out.println("Time Taken: " + (endTime - startTime));
}
}
假如有三个不同的Interceptor,他们的配置如下,则其默认执行顺序为其注册顺序。当然,也可以使用 InterceptorRegistry#order(int) 方法指定执行顺序,值越小优先级越高。
@Configurationpublic
class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin");
registry.addInterceptor(new AdminInterceptor()).addPathPatterns("/admin/*").excludePathPatterns("/admin/oldLogin");
}
}
3、NewbeeMall - Interceptor鉴权 - 代码审计
3.1、 确定鉴权方式
翻阅 pom.xml 和 External Libraries,未观察到 Shiro、JWT 关键字,排除使用 Shiro、JWT 进行鉴权的可能。继续翻阅项目文件,观察到 interceptor 文件夹下有三个文件:AdminLoginInterceptor、NewBeeMallCartNumberInterceptor、NewBeeMallLoginInterceptor。继续搜索注册关键字 "registry.addInterceptor" 定位到 Interceptor 的配置文件 NeeBeeMallWebMvcConfigurer,最终确定该项目使用 Interceptor 进行鉴权。
3.2、AdminLoginInterceptor >> preHandle >> uri.startsWith
分析 AdminLoginInterceptor 的 preHandle 方法,得知若请求的 URI 以 "/admin" 开头且 Session 中的 loginUser 属性为 null,则进行拦截。
3.3、漏洞利用
由于 Session 无法伪造,那么可以从 URI 入手,试想若构造一个不以 /admin 开头的 URI,那不就可以放行了吗?于是构造 URI 为 /;/admin 或 //admin(不影响解析)成功绕过 Interceptor 进入后台。
0x03 Filter鉴权审计 - 华夏ERP进销存系统
1、项目介绍 - 华夏ERP
华夏 ERP 是目前唯一完整开源的进销存系统,具备进销存 + 财务的功能(只有后台)
核心框架为 SpringBoot 2.0.0,持久层框架为 Mybatis 1.3.2,日志管理为 Log4j 2.10.0
项目环境为:Mysql5.7+、JDK1.8、Maven3.2.3
下载:https://github.com/jishenghua/jshERP
2、华夏ERP - Filter - 代码审计
2.1、确定鉴权方式
翻阅 pom.xml 和 External Libraries,未观察到 Shiro、JWT 关键字,排除使用 Shiro、JWT 进行鉴权的可能。继续翻阅项目文件,观察到 filter 文件夹下有文件:LogCostFilter,其 urlPatterns 为匹配所有,分析 doFilter 方法确实含有于鉴权相关的代码逻辑,所以确定项目使用 Filter 进行鉴权。
2.2、LogCostFilter >> urlPatterns >> doFilter >> requestUrl,ignoredList,allowUrl
分析 doFilter 方法,得出其放行和拦截的逻辑如下:
- 检查用户是否已登录,如果已登录则放行
- 放行登录页和注册页
- 检查是否为忽略列表中的URL,如果是则放行
- 检查是否为允许列表中的URL,如果是则放行
- 否则,重定向到登录页
分析 init 方法,得知以下信息:
- ignoredList << ignoredUrl = ".css#.js#.jpg#.png#.gif#.ico"
- allowUrls << filterPath = "/user/login#/user/registerUser"
2.3、漏洞利用
根据上面得到的信息,从 URI 入手,构造 URI 为:
/login.html/../account/getAccount
/register.html/../account/getAccount
/ch4ser.css/../account/getAccount
/ch4ser.jpg/../account/getAccount
/user/login/../../account/getAccount
/user/registerUser/../../account/getAccount
........
BurpSuite抓包修改URI,成功在未登录情况下进入后台。
0x04 Shiro鉴权审计 - Tumo博客系统
1、项目介绍 - Tumo博客系统
Tumo Blog 是一个简洁美观的博客系统,基于SpringBoot2.X + Vue.js。
下载:https://github.com/TyCoding/tumo
2、Tumo - Shiro - 代码审计
2.1、确定鉴权方式
翻阅 pom.xml 和 External Libraries,观察到 Shiro 关键字,确定项目使用 Shiro 进行鉴权。
2.2、查看Shiro配置信息
查看 tumo.properties,发现有关 Shiro 的配置,其中 anon_url 为可匿名访问的路径(一般代表不需要鉴权)。不同于 Shiro 本身的漏洞,这里的鉴权漏洞是由于开发、运维不当的 Shiro 配置所造成的。
2.3、漏洞利用
根据Shiro配置信息,寻找利用点,比如 /comment/** 是不需要鉴权的。全局搜索 "/comment" 相关的 Controller 文件,定位到 CommentController。
测试删除评论,路由为 /comment/{id},提交方式为 DELETE。
删除前,数据库存储的评论如下:
BurpSuite抓包修改提交方式为 DELETE,成功删除评论,如下:
0x05 JWT鉴权审计 - FastCMS
1、项目介绍 - FastCMS
FastCMS 基于 SpringBoot 进行插件式开发,具有极强的扩展性,内置一套完整的 CMS 建站系统,同时也支持博客,论坛,商城等功能。
下载:https://gitee.com/xjd2020/fastcms
2、JWT鉴权漏洞审计思路
一般来说,空加密和未校验签名很少见,除非是新手开发、运维,比较常见的是默认密钥未修改和密钥存在被爆破的可能。
- 生成时使用空加密(逻辑代码问题)
- 服务端未校验签名(逻辑代码问题)
- 密钥默认未被修改(搭建后未修改)
- 密钥爆破可能性大(密钥过于简单)
3、FastCMS - JWT - 代码审计
3.1、确定鉴权方式
翻阅 pom.xml 和 External Libraries,观察到 JWT 相关 Dependency 信息。
除此之外,BurpSuite 抓包也能看到很明显的 JWT 流量特征(eyJ)
3.2、审计流程
分析 JwtAuthTokenFilter,它主要做了以下工作:
1、在请求到达控制器之前检查JWT令牌,并将令牌中的认证信息设置到Spring Security
2、过滤器根据请求URI的前缀判断是否需要进行身份验证。
3、如果需要验证且JWT令牌有效,它将继续执行过滤器链;否则,它将返回相应的错误响应。
JWT 的验证到底有没有问题,关键就在于 tokenManager 的各个方法是否存在问题,于是跟踪到了 DelegatingTokenManager,检查其各个方法的代码,发现不存在空加密或未校验签名的问题。
转而查看 application.yml,发现密钥 secret-key 为官方默认的,也就是说搭建后未修改过。
3.3、漏洞利用
利用默认密钥,生成管理员账户的 JWT(注意修改过期时间 exp)
BurpSuite 抓包修改 JWT 值,成功进入管理员后台