基于路由转发导致的权限认证绕过漏洞分析

基于路由转发导致的权限认证绕过漏洞分析

原创 Mmuz 奇安信天工实验室 2025-05-21 03:31

一、前  言

二、路由转发导致权限认证绕过

三、漏洞分析

四、总  结

前  言

在 Web 应用程序的开发过程中,安全问题始终是至关重要的。权限认证作为保障系统安全的重要防线,能够确保只有经过授权的用户才能访问特定的资源。然而,由于开发人员的疏忽或者对某些技术细节的理解不够深入,可能会引发一些安全漏洞,导致权限认证机制被绕过。

本文将介绍一种基于转发机制的权限认证绕过漏洞模式。在实际的 Web 应用中,常常会使用过滤器
(Filter

或者Authenticator
做权限认证。但当应用中存在一些可以未授权访问的代码允许用户通过请求参数指定转发的目标 URL 时,就可能会出现权限认证被绕过的情况。这种漏洞可能会使未授权的用户访问到本应受保护的资源,从而对系统的安全性造成严重威胁。接下来,我们将详细探讨这种漏洞模式的具体细节。

路由转发导致权限认证绕过

01

Filter机制

Java Filter
 是一个实现了 
javax.Servlet.Filter
 接口的 Java 类,它可以对客户端的请求进行拦截,在请求到达目标资源(如 
Servlet

JSP
等)之前进行一些预处理操作,也可以在服务器返回响应给客户端之前对响应进行后处理操作。常用在权限认证 、字符编码处理、日志记录等场景。

一般在
web.xml
中配置如下:

关键点在于
dispatcher
选项,作用是指定过滤器的触发条件(即请求的转发类型)。
可选值
如下:
REQUEST
(默认配置):当客户端直接发送请求时触发过滤器。

  • FORWARD
    :当请求被转发(使用 
    RequestDispatcher#forward

方法)时触发过滤器。

  • INCLUDE
    :当请求被包含(使用 
    RequestDispatcher#include
     方法)时触发过滤器。

  • ASYNC
    :当异步请求触发时(用于 
    Servlet 3.0+
     的异步处理场景)。

  • ERROR
    :当发生错误并进入错误页面时触发过滤器。

02

Authenticator机制

Authenticator
不是
Servlet
标准,是Tomcat 和 
Jetty
 各自私有实现中的一个概念,用于实现 
Servlet
 容器的认证机制。

Servlet
容器一般会根据 
web.xml
 中的配置(
login-config
 和 
security-constraint
)来决定何时对请求进行认证。

认证方式可以自定义,也可以使用自带的认证方式:
– BASIC:浏览器弹出用户名密码框,使用 
HTTP Basic
 认证头。

  • FORM:自定义表单登录页,用户名密码提交到服务器。

  • DIGEST:
    HTTP Digest
     认证(不常用)。

  • CLIENT-CERT:基于客户端证书的 
    SSL
     认证。

如下是个简单的配置例子,限制了
/admin/*
资源必须先通过
FORM
认证:

Tomcat中的
Authenticator
都继承
AuthenticatorBase
实现
org.apache.catalina.Authenticator
接口,以
valve
(阀门)的形式存在于
Pipeline
(管道)中。每一层容器中都有自己的
Pipeline
,它将一系列的 
Valve
接在一起,形成一个链式调用。当请求到达顶层容器 
Engine
 后,沿着 
Engine → Host → Context → Wrapper
 传递,进入某层容器时该容器的 
Pipeline
 中的 
Valve
 就会依次被调用对请求和响应进行特定的处理。
FormAuthenticator
属于
context
层的
valve
。当请求到达
Authenticator
时就会在
AuthenticatorBase
根据配置决定是否需要认证。

1.png

Jetty
中的
Authenticator
都继承
LoginAuthenticator
实现
org.eclipse.Jetty.security.Authenticator
接口。启动时解析 
web.xml 
中 

或者代码中的配置,自动为 
WebApp
 配置 
SecurityHandler
,创建对应的 
Authenticator

Jetty
 中所有的请求处理逻辑都以 
Handler
 的形式组织和串联在一起,构成一条请求处理链(
Handler Chain
),当请求到达
SecurityHandler
时,就会根据配置决定是否调用对应的
Authenticator
进行认证。

2.png

Authenticator

Filter
对比:

特性

Authenticator

Filter(Java EE 标准)

所属层级

Servlet 容器层

Web 应用层

启用方式

web.xml 中配置 <login-config>

web.xml 或注解 @WebFilter

认证触发时机

容器处理请求初期,早于 Filter 执行

请求进入应用后、在 Servlet 执行前执行

03

路由转发机制

RequestDispatcher
 是 
Java Servlet API
 中的一个接口,内部有
forward

include
两个方法:

3.png

它的主要作用是:
在服务器内部将一个请求跳转(forward)或包含(include)到另一个资源(如 Servlet、JSP、HTML)中进行处理。
区别于重定向,它不会让客户端发起新的请求,属于服务器端的“内部转发”机制。

4.png

两者的区别在于
forward
由目标资源直接生成响应,
include
后会将目标资源生成的响应包含在当前的
Servlet
响应中一起发送给客户端。

04

认证绕过

在转发到目标资源前,需要根据 
url-pattern
和  
DispatcherType
类型匹配重新组装
FilterChain
以便于对请求进行预处理。

Tomcat
中只经过
FilterChain
的处理,并不会经过比
Filter
更底层的
valve
等处理。

5.png

Jetty

checkSecurity
对于
forward

include
类型的请求默认返回
false
,所以会直接调用
handler.handle
,导致根本不用过
Authenticator
校验。
ASYNC

REQUEST
才会为
true
,从而进入
if
分支进行看是否需要
Authenticator
认证校验。

6.png

7.png

因此存在两种路由转发导致的权限认证绕过的模式。

Filter类型认证绕过

Filter

dispatcher
选项是经常被开发忽略的点,常常是不配置,或者只配置
REQUEST
方式,这就导致存在安全隐患。当同时满足如下条件时则可以权限认证绕过:
1. 权限认证是在
Filter
进行,且
dispatcher
选项中未配置
FORWARD
或者
INCLUDE

  1. 存在未授权的代码通过未配置选项对应的
    forward
    或者
    include
    方法向某个
    url
    转发请求且
    url
    可控。

Authenticator等更底层的权限认证绕过

  1. 权限认证使用比
    Filter
    等更底层的认证方式,如
    Tomcat

    Valve
    或者
    Jetty

    Authenticator

  2. 存在未授权的代码通过
    forward
    或者
    include
    方法向某个
    url
    转发请求且
    url
    可控。

一个Filter类型的小例子

DspServlet
代码如下,
service
方法使用
req.getRequestDispatcher
方法根据
url
获取
RequestDispatcher
对象后调用
forward
进行路由转发,
url
可控。

screenshot (3).png

AdminServlet
代码如下:

screenshot (4).png

当直接访问
/admin
时,会被
AuthFilter
拦截:

8.png

但是通过
DspServlet
路由转发的方式访问则能绕过
AuthFilter
拦截,此时从
DspServlet#service


AdminServlet#service

的调用栈中可以看到不经过
AuthFilter#Filter

9.png

10.png

根据上述例子可知,路由转发时需要先根据
url
匹配某个
Servlet-mapping

url-pattern
的获取
javax.Servlet.RequestDispatcher
,那么如何获取呢?通常有如下几种常用的方式:
– javax.servlet.ServletRequest#getRequestDispatcher

  • javax.servlet.ServletContext#getRequestDispatcher

  • javax.servlet.ServletContext#getNamedDispatcher

  • jsp中运行时包含和转发的形式:


Tomcat
跟踪调用流程就能发现:
– javax.Servle
t.ServletRequest#getRequestDispatcher

最终还是通过调用
javax.Servlet.ServletContext#getRequestDispatcher

去获取
RequestDispatcher

  • jsp
    的运行时包含和转发的形式其实是调用
    javax.Servlet.ServletRequest#getRequestDispatcher

方法去完成的

接下来看
Tomcat
中对
path
进行处理的关键方法:

org.apache.catalina.connector.Request#getRequestDispatcher

中判断
path
中有

,则直接截断。

screenshot (9).png

org.apache.catalina.core.ApplicationContext#getRequestDispatcher

中去除
path
中的参数部分后调用
stripPathParams

normalize
进行处理:

screenshot (10).png

org.apache.catalina.core.ApplicationContext#stripPathParams

的作用就是清除
path

;xxx/
(不包括
/
)的部分:

screenshot (11).png

org.apache.Tomcat.util.http.RequestUtil#normalize

方法的作用就是如果
path

/.
或者
/..
结尾,则在末尾添加
/
再对
//

/../ 

/./
做规范化处理:

screenshot (12).png

org.apache.catalina.core.ApplicationContext#getNamedDispatcher

中通过
name
获取当前
context
的子容器:


Tomcat
的中结构如下,所以
context
的子容器是
Wrapper
,每个
Wrapper
负责管理一个具体的
Servlet
类的生命周期。
Wrapper

name
对应
Servlet-name

根据上述分析可知:
– getNamedDispatcher
是根据
Servlet-name
进行转发的。

  • 其他
    getRequestDispatcher
    是通过对一个
    path
    经过处理后能匹配一个
    Servlet-mapping

    url-pattern
    进行转发的。
    Request
    类和
    ApplicationContext
    类的处理规则表如下:

原始path

Request

ApplicationContext

/a/./admin#xxx

/a/./admin

/a/admin

/a/./admin;yyy#xxx

/a/./admin;yyy

/a/admin

/a;xxx/admin.jsp;yyy

/a;xxx/admin.jsp;yyy

/a/admin.jsp

/a/../admin;yyy#xxx

/a/../admin;yyy

/admin

/a/./admin/..

/a/./admin/..

/a

/a/./admin/.

/a/./admin/.

/a/admin

/a;xxx/admin.jsp

/a;xxx/admin.jsp

/a/admin.jsp

/abc;xxx/yy

/abc;xxx/yy

/abc/yy

漏洞分析

01

CVE-2022-31692  Spring Security认证绕过漏洞

5.7.0 <Spring Security<5.7.5和 5.6.0 <Spring Security<5.6.9
 版本,可以通过forward或include的dispatcher类型绕过授权规则。

如果一个应用的
spring security
配置如下,定义了一个有
ADMIN
角色的用户,并配置
/admin
需要有
ADMIN
角色才能访问。

screenshot (15).png

对于如下
controller
,当不登录或者用户没权限时访问
/admin
会提示未授权,访问
/dsp
时却能访问到
/admin
资源:

screenshot (16).png

其核心原因是进行权限认证关键类
AuthorizationFilter
继承自
OncePerRequestFilter
 ,而
OncePerRequestFilter
 的作用就是保证其子类在每次请求中只执行一次,所以当访问
/dsp

AuthorizationFilter
已经触发一次,
forward:/admin
时将不再触发认证流程导致认证绕过。

11.png

02

CVE-2022-40664 Apache Shiro身份认证绕过漏洞

Apache Shiro<1.10.0
时,通过RequestDispatcher include或forward可以造成身份验证绕过漏洞。

一个应用的
Shiro
配置部分代码如下,指定
/admin
需要认证,
/dsp
不需要:

screenshot (17).png

当不登录时访问
/admin
会提示未授权,访问
/dsp
时却能访问到
/admin
资源:

screenshot (18).png

该漏洞核心原因和
Spring security
类似,当
Forward

request
已经有
alreadyFilteredAttributeName
标志了,所以就不进入
Shiro
内部
Filter
链检查当前
url
是否需要认证,所以导致认证绕过。

12.png

03

CVE-2021-44515 ManageEngine Desktop Central身份认证绕过漏洞

ManageEngine Desktop Central<10.1.2127.18
容易受到身份验证绕过攻击,导致在服务器上远程执行代码。

该漏洞的关键点在于
StateFilter
的路由转发。
web.xml
的配置如下:

13.png

doFilter
方法中获取
path
后通过
request.getRequestDispatcher(path).forward
进行转发。

14.png

getForwardPath
中截取
requestURI
的一部分返回,因此是可控的。

15.png

ChangeAmazonPasswordServlet
可以直接修改用户密码。

16.png


web.xml
配置如下:

17.png

18.png

同时在

中配置
/changeDefaultAmazonPassword
资源不限制角色但需要登录才能访问,认证是在
CUSTOMFORM856
中做的。

CUSTOMFORM856
是自定义的
Authenticator
,以
valve
的形式生效于
Filter
之前。

19.png

20.png


中没有配置
/STATE_ID/*
资源,不会经过
CUSTOMFORM856
认证校验,
Forward
方式转发到
/changeDefaultAmazonPassword
只会经过相应的
Filter
,所以可以权限认证绕过。对应的部分调用栈如下:

21.png

04

CVE-2024-33535 zimbra本地文件包含漏洞

Zimbra Collaboration(ZCS)9.0和10.0中发现了一个问题。该漏洞涉及web应用程序中未经身份验证的本地文件包含(LFI),具体影响了packages参数的处理。攻击者可以利用此漏洞在没有身份验证的情况下包含任意本地文件,从而可能导致对敏感信息的未经授权的访问。该漏洞仅限于特定目录中的文件。

该漏洞是由于
/public/admin.jsp
文件使用

标签进行动态包含
page
,其中
pname
可控,虽然
zimbra

Servlet
容器是
Jetty
,但也可以
../
目录穿越和
;
截断
psuffix
,从而达到访问非
jsp
类型的
url

22.png

web.xml
中配置的
/downloads/*
路径会被
org.eclipse.Jetty.Servlet.DefaultServlet
处理,但需要经过
ZimbraAuth
的认证。

23.png

Jetty-env.xml
使用 
ZimbraAuthenticatorFactory
 创建自定义认证器
ZimbraAuthenticator
,只对某些路径(如 
/downloads/*
)启用认证。

24.png

25.png

26.png

当不提供用户凭证访问时会被
zimbra
自定义的
ZimbraAuthenticator
拦截,提示未授权。

27.png

当通过
public/admin.jsp
路由转发时则会绕过
ZimbraAuthenticator
拦截。

28.png

总  结

本文介绍了
Java

Filter
机制、
Tomcat
以及
Jetty
中的
Authenticator
机制,深入剖析了路由转发导致权限认证绕过的原理,并分析了
Tomcat
中对于要转发的
url
的处理特性,举了几个CVE的例子对该漏洞模式进行详细说明。

参考链接

1. Commit 1f481aa

2. Class OncePerRequest

3. CVE-2022-31692

【版权说明】

【版权说明】

本作品著作权归Mmuz
所有

未经作者同意,不得转载

头像.jpg

Mmuz

天工实验室安全研究员

专注于代码审计、Web安全

往期回顾

01

隐匿与追踪:Rootkit检测与绕过技术分析

02

二进制混淆对抗技术研究

03

WordPress插件认证绕过与权限提升漏洞实例分析

04

Connexion API内存马植入研究

每周三更新一篇技术文章  点击关注我们吧!