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。