首页 > 技术文章 > spring boot 整合shiro 实践(顺便复现下CVE-2020-13933)

fczlm 2021-01-25 18:02 原文

以前遇到过 apache shiro的反序列化漏洞,虽然利用poc都能执行,但是 apache shiro 到底是干嘛用的一直也没研究。今天学习下这个框架的使用,为之后渗透有apache shiro的服务做准备。

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

shiro主要有三大功能模块:

1. Subject:主体,一般指用户。
2. SecurityManager:安全管理器,管理所有Subject,可以配合内部安全组件。(类似于SpringMVC中的DispatcherServlet)
3. Realms:用于进行权限信息的验证,一般需要自己实现。

简单理解就是做用户认证和权限管理的

首先创建一个spring boot项目,引入spring web依赖

pom.xml引入相关依赖

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.5.3</version>
</dependency>

  application.properties配置shiro的基本信息

shiro.sessionManager.sessionIdCookieEnabled=true
shiro.sessionManager.sessionIdUrlRewritingEnabled=true
shiro.unauthorizedUrl=/unauthorizedurl
shiro.web.enabled=true
shiro.successUrl=/index
shiro.loginUrl=/login

  

创建realm,实现简单用户认证

public class MyRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        if (!"test".equals(username)) {
            throw new UnknownAccountException("账户不存在!");
        }
        return new SimpleAuthenticationInfo(username, "test123", getName());
    }
}

  

在配置ShiroConfig

@Configuration
public class ShiroConfig {
    @Bean
    MyRealm myRealm() {
        return new MyRealm();
    }
    @Bean
    DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm());
        return manager;
    }
    @Bean
    ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        definition.addPathDefinition("/doLogin", "anon");
        definition.addPathDefinition("/hello/*", "authc");
        return definition;
    }
}

  

controller:

@RestController
public class LoginController {
@PostMapping("/doLogin")
public void doLogin(String username, String password) {
Subject subject = SecurityUtils.getSubject();
try {
subject.login(new UsernamePasswordToken(username, password));
System.out.println("登录成功!");
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("登录失败!");
}
}
@GetMapping("/hello")
public String hello() {
return "hello";
}

@GetMapping("/hello/{name}")
public String hellotest(@PathVariable("name") String name) {
return name;
}

@GetMapping("/test3/{name}")
public String test3(@PathVariable("name") String name) {
return name;
}

@GetMapping("/login")
public String login() {
return "please login!";
}
}

  

运行程序,访问http://127.0.0.1:8080/hello/test都会跳转到登录http://127.0.0.1:8080/login。

post请求:

POST http://127.0.0.1:8080/doLogin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
cache-control: no-cache
Postman-Token: 7e5a8744-9a42-4c9b-aae5-2cc1484c2927
User-Agent: PostmanRuntime/7.4.0
Accept: */*
Host: 127.0.0.1:8080
cookie: JSESSIONID=91AE16DC971D88083E6396B8CF521CE1
accept-encoding: gzip, deflate
content-length: 30
Connection: keep-alive

username=test&password=test123

  

返回登录成功。

之后的

http://127.0.0.1:8080/hello

http://127.0.0.1:8080/hello/test

就都可以正常返回了。不得不说这样做权限管控确实很方便。不用担心会有未授权访问漏洞了。

 

但是出了

shiro < 1.6.0的认证绕过漏洞(CVE-2020-13933)

通过一些特殊字符编码可以绕过认证

正常访问http://127.0.0.1:8080/hello/test 需要跳转

 

 

127.0.0.1:8080/hello/%3btest 即可绕过权限验证

 

 

测试发现1.4.0没有这个问题,应该也是特定版本有这样的问题。那么可以去找一些使用了shiro的系统,通过js提取相关的url地址,如果做了认证访问限制的,即可加入这样特殊字符查看能否绕过

 

推荐阅读