【vulhub】CVE-2020-1957 Apache Shiro Servlet未授权访问

漏洞描述

1. 漏洞编号:CVE-2020-1957

2. 影响版本:Apache Shiro < 1.5.1

3. 漏洞产生原因:

Shiro拦截器

Shiro框架通过拦截器功能来实现对用户访问权限的控制和拦截。Shiro中常见的拦截器有anon,authc等拦截器。

1.anon为匿名拦截器,不需要登录就能访问,一般用于静态资源,或者移动端接口

2.authc为登录拦截器,需要登录认证才能访问的资源。

用户可以在Shiro.ini编写匹配URL配置,将会拦截匹配的URL,并执行响应的拦截器。从而实现对URL的访问控制,URL路径表达式通常为ANT格式。如下配置,访问 /index.html主页的时候,Shiro将不会对其进行登录判断,anon拦截器不需要登录就能进行访问。而对于/user/xiaoming 等 /user/xiaogang等接口,authc拦截器将会对其进行登录判断,有登录认证才能访问资源。

[urls]
/index.html = anon
/user/** = authc

Shiro的URL路径表达式为Ant 格式,路径通配符支持?***。

?:匹配一个字符
*:匹配零个或多个字符串
**:匹配路径中的零个或多个路径

其中*表示匹配零个或多个字符串,/*可以匹配/hello,但匹配不到/hello/因为*通配符无法匹配路径。假设/hello接口设置了authc拦截器,访问/hello将会被进行权限判断,如果请求的URI为/hello/呢,/*URL路径表达式将无法正确匹配,放行。然后进入到spring(Servlet)拦截器,spring中/hello形式和/hello/形式的URL访问的资源是一样的。

漏洞成因

路径解析差异
Shiro 的 PathMatchingFilterChainResolver 使用简单的字符串匹配逻辑(基于 AntPathMatcher),而 Spring 的 AntPathMatcher 支持更灵活的路径标准化(如忽略结尾的 / 或解析 ; 后的内容)。例如:

Shiro 将 /admin/ 和 /admin 视为不同路径,而 Spring 可能视为同一路径。
Shiro 在处理分号 ; 时会截断后续内容(如 /admin;xxx 解析为 /admin),而 Spring 可能保留完整路径。

配置缺陷
Shiro 的过滤器链配置若未覆盖所有可能的路径变体(如未配置 /admin/** 或 /admin/),攻击者可构造 /admin/ 或 /admin;xxx 绕过校验。

漏洞复现

启动环境

docker-compose build
docker-compose up -d

环境启动后,访问http://your-ip:8080即可查看首页

使用bp抓包,访问/admin目录,出现302,会跳转到登录接口:

 

 访问/xxx/..;/admin/目录,绕过权限校验,访问到管理页面

 

 

 

其中以上处理过程:

  1. 客户端请求URL: /xxxx/..;/admin/

  2. shrio 内部处理得到校验URL为 /xxxx/..,校验通过

  3. springboot 处理 /xxxx/..;/admin/ , 最终请求 /admin, 成功访问了后台请求.

 修复方案

1.升级1.5.2版本及以上

  在shiro1.5.2版本已加入的过滤器规则:
 @Test
    void testGetRequestUriWithServlet() {
        dotTestGetPathWithinApplicationFromRequest("/", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("", "servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("/", "servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("//", "servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("//", "//servlet", "//foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("/context-path", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("//context-path", "//servlet", "//foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("//context-path", "/servlet", "/../servlet/other", "/servlet/other")
        dotTestGetPathWithinApplicationFromRequest("//context-path", "/asdf", "/../servlet/other", "/servlet/other")
        dotTestGetPathWithinApplicationFromRequest("//context-path", "/asdf", ";/../servlet/other", "/asdf")
        dotTestGetPathWithinApplicationFromRequest("/context%2525path", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("/c%6Fntext%20path", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("/context path", "/servlet", "/foobar", "/servlet/foobar")
        dotTestGetPathWithinApplicationFromRequest("", null, null, "/")
        dotTestGetPathWithinApplicationFromRequest("", "index.jsp", null, "/index.jsp")
    }
2.尽量避免使用*通配符作为动态路由拦截器的URL路径表达式。
posted @ 2025-05-16 22:58  Antoniiiia  阅读(6)  评论(0)    收藏  举报