shiro < 1.6.0的认证绕过漏洞分析(CVE-2020-13933) – 安全客,安全资讯平台 | xxxshiro < 1.6.0的认证绕过漏洞分析(CVE-2020-13933) – 安全客,安全资讯平台 – xxx
菜单

shiro < 1.6.0的认证绕过漏洞分析(CVE-2020-13933) – 安全客,安全资讯平台

八月 21, 2020 - 安全客

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

 

0x00 什么是shiro

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

 

0x01 环境搭建

1、去https://start.spring.io/使用springboot脚手架搭建一个java8的springboot项目

2、用IDEA打开该项目,目录结构与文件如下:

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

3、创建MyRealmNameControllerShiroConfig三个class文件。

4、pom.xml增加对应的dependency

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.3.3.RELEASE</version>         <relativePath/> <!-- lookup parent from repository -->     </parent>     <groupId>com.example</groupId>     <artifactId>demo</artifactId>     <version>0.0.1-SNAPSHOT</version>     <name>demo</name>     <description>Demo project for Spring Boot</description>      <properties>         <java.version>1.8</java.version>     </properties>      <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-devtools</artifactId>             <optional>true</optional>         </dependency>          <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>             <exclusions>                 <exclusion>                     <groupId>org.junit.vintage</groupId>                     <artifactId>junit-vintage-engine</artifactId>                 </exclusion>             </exclusions>         </dependency>         <dependency>             <groupId>org.apache.shiro</groupId>             <artifactId>shiro-web</artifactId>             <version>1.5.3</version>         </dependency>         <dependency>             <groupId>org.apache.shiro</groupId>             <artifactId>shiro-spring</artifactId>             <version>1.5.3</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-web</artifactId>             <version>5.2.5.RELEASE</version>         </dependency>         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>servlet-api</artifactId>             <version>2.5</version>         </dependency>     </dependencies>      <build>         <plugins>             <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>                 <configuration>                     <fork>true</fork>                 </configuration>             </plugin>         </plugins>     </build>  </project> 

ShiroConfig.java代码如下:

package com.example.demo;  import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 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     MyRealm myRealm(){         return new MyRealm();     }     @Bean     SecurityManager securityManager(){         DefaultWebSecurityManager manager = new DefaultWebSecurityManager();         manager.setRealm(myRealm());         return manager;     }     @Bean     ShiroFilterFactoryBean shiroFilterFactoryBean(){         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("/test/*","authc");         bean.setFilterChainDefinitionMap(map);         return bean;      } } 

NameController代码如下:

package com.example.demo;  import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController;  @RestController public class NameController {      @GetMapping("/test/{name}")     public String test(@PathVariable String name){         return "s1111";     }      @GetMapping("/test/")     public String test2(){         return "test2";     } } 

MyRealm代码如下:

package com.example.demo;  import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection;  public class MyRealm extends AuthorizingRealm {     @Override     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {         return null;     }      @Override     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {         return null;     } } 

 

0x02 poc测试

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

原本需要认证的test/{name}可以访问到了

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

证明漏洞利用成功。

 

0x03 漏洞原理分析

根据shiro历史上的认证绕过漏洞,本质问题就是springboot对url的处理和shiro的处理不一致导致的认证绕过。
其中shiro的url处理的问题都出在org/apache/shiro/web/util/WebUtils.java类下面,在return

    public static String getPathWithinApplication(HttpServletRequest request) {         return normalize(removeSemicolon(getServletPath(request) + getPathInfo(request)));     } 

断点,
然后我们去springboot的处理url的地方进行断点,org/springframework/web/util/UrlPathHelper.java

在return uri;进行

    private String decodeAndCleanUriString(HttpServletRequest request, String uri) {         uri = removeSemicolonContent(uri);         uri = decodeRequestString(request, uri);         uri = getSanitizedPath(uri);         return uri;     } 

断点。

访问/test/%3bname,先来到shiro的url处理块,

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

根据图纸可知,获取到的url在处理前已经进行了一次urldecode。然后在进入removeSemicolon操作,最后结果集在交给normalize操作。

根据计算器可知removeSemicolon会把url里;后面的内容给删除(包括;)

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

跟进removeSemicolon看看。

实现代码如下:

    private static String removeSemicolon(String uri) {         int semicolonIndex = uri.indexOf(';');         return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);     } 

确实是把;后面的内容给删除(包括;)了。

一路F8,最后果然把/test/赋值给requestURI变量了。

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

根据测试当初访问/test/

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

可以看到,如果test目录的话,是默认有权限访问的,但是/test/后面的路由是需要验证的。

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

接着我们来到springboot,看看springboot是怎么处理URL的问题。

shiro &lt; 1.6.0的认证绕过漏洞分析(CVE-2020-13933) - 安全客,安全资讯平台

uri取到的是/test/;name,可以看到springboot对url做了三个操作后才返回的,removeSemicolonContent,decodeRequestString,getSanitizedPath

这是简单对比下shiro的对url的操作顺序:

因为shiro的处理和springboot的处理顺序不同,导致我们构造的poc在shiro侧理解的是访问的/test/,/test/我们本身就没有限制权限,放过了这个原本需要认证权限的请求,而springboot侧则是访问的是/test/;name,然后springboot把;name当做一个字符串去寻找对应的路由,返回了对应的字符串。

 

0x04 总结

此漏洞主要是两个组件之间对某个关键信息处理的逻辑未进行统一约定,可以理解成前后端对同一个信息处理的不同步导致的安全漏洞。

同样的认证绕过在shiro历史上出现过好几次,具体可以去参考链接学习。

 

0x05 参考


Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51