shiro-未授权

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. 环境搭建:

目录如下:

image-20240312135436085

标准的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需要进行登录:

image-20240312140028231

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

image-20240312140157400

抓包:

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

image-20240312140237706

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

image-20240312140327150

3.漏洞分析:

image-20240312151145191

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

image-20240312151432310

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

image-20240312151521127

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

image-20240312151846609

调用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

image-20240312153255059

返回的路径是/abc

image-20240312153139709

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

image-20240312153813074

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


shiro-未授权
https://pow1e.github.io/2024/05/28/漏洞中间件复现/shiro/shiro-未授权/
作者
pow1e
发布于
2024年5月28日
许可协议