shiro 1.4.1
简述:主要是通过/请求路径/
即可实现bypass,越权访问。
适用范围:
版本<=1.4.1
poc:
shiro配置 |
请求资源路径 |
bypass路径 |
说明 |
map.put(“/admin”,”auth”) |
/admin |
/admin/ |
/admin 路径需要登陆才可以访问,但是使用/admin/ 可以绕过,因为shiro匹配不到/admin/ ,但是sb可以将末尾的/ 去掉。 |
map.put(“/admin/**”,”auth”) |
/admin/page |
/admin;/page |
/admin/**/ 正常匹配这个路径是登录,但是shiro处理; 会把; 后的路径都去除,即变成/admin 因此匹配不到/admin/** ,sb则会去除多余; 变成/admin/page 正常访问。 |
1. 环境搭建:
目录如下:

标准的springboot环境,依赖如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.4.1</version> </dependency>
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency>
</dependencies>
|
config配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.hme.config;
import com.hme.realm.Realm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap; import java.util.Map;
@Configuration public class ShiroConfig { @Bean Realm realm() { return new Realm(); }
@Bean DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") Realm realm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(realm); return manager; }
@Bean ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager); bean.setLoginUrl("/login"); bean.setSuccessUrl("/index"); bean.setUnauthorizedUrl("/unauthorizedurl"); Map<String, String> map = new LinkedHashMap<>(); map.put("/doLogin", "anon"); map.put("/admin/**", "authc"); bean.setFilterChainDefinitionMap(map); return bean; } }
|
主要自定义了relam,然后配置拦截路径,其中
/admin/**
路径的是authc
需要登录才可以访问的。
/doLogin
是匿名访问的。
设置了登录重定向的路径为/login
设置了登陆成功路径为/index
2. 复现过程:
当直接访问/admin
需要进行登录:

请求/doLogin?username=pow1e&password=123456
登录后再次访问后即可访问/admin

抓包:
讲cookie删除后是不会访问成功的

访问/admin/
,在需要越权的路径后添加/
即可越权成功。

3.漏洞分析:

这里的filterChainManager.getChainNames()
获取到的是shiro中鉴权的路径

而这里的requestURI是servlet中获取到的uri:

由于需要鉴权的/admin
在这里匹配不到返回了null,然后进入Spring-Web的DispatcherServlet中,在DispatcherServlet的doDispatch方法中获取Handler:

调用getHandler获取handler,后续在PathPattern#match
方法中对/admin/list/
和 /admin/list
的匹配都会返回 true。
查看资料还看到存在另一个poc,decodeAndCleanUriString
方法,主要是截取uri中的;
号,判断是否存在,如果是不为-1(存在)则会截取当前uri的第0当前截取到的';'
索引对应的下标位置,如果不存在;
则直接返回原uri。
就是说/abc;/admin
会被shiro处理成/abc
/abc
则会处理成/abc
假如shiro中需要鉴权的路径为/admin
,请求的路径为/xxx;/admin
,就会被shiro处理成/xxx
然后进去匹配当前路径是否需要鉴权,但是只有/admin
才需要鉴权,所以就绕过了shiro的鉴权。
shiro处理/abc;/admin

返回的路径是/abc

到springboot中会当前uri进行处理的结果是/abc/admin

所以在shiro1.4.0,shiro拦截中写的是/admin/*
,正常是访问/admin/page
会被拦截的,但是使用;
分号阻隔,shiro会处理成/admin
,则会绕过/admin/*
的匹配规则,而springboot则会处理成/admin/page
。