Skip to content

Latest commit

 

History

History
144 lines (110 loc) · 6.15 KB

File metadata and controls

144 lines (110 loc) · 6.15 KB

CVE-2010-3863权限绕过分析

初识shiro

Apache Shiro™是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。借助 Shiro 易于理解的 API,您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。

从官方简介中可以得知 shiro 是一套权限管理框架,在 shiro 框架中有以下三个核心概念模块:SubjectSecurityMangerRealmsimage-20210418162523103

  • Subject:当前正在执行的用户
  • SecurityManger:安全管理器,管理所有用户的操作,是 shiro 架构的核心
  • Realm:封装数据源,充当 shiro 与应用程序安全数据之间的桥梁,当需要与安全相关的数据(如用户帐户)进行实际交互以执行身份验证(登录)和授权(访问控制)时,为其提供身份验证或者授权。

因此一次 请求--> 认证 --> 授权的流程为:

  1. web 应用程序获取当前的Subject并调用该Subject的校验方法;
  2. Subject传递校验到SecurityManger进行处理并进行判断;
  3. SecurityManger调用Realm获取配置信息,通过该配置信息判断当前的Subject所属角色是否能够进行操作。

漏洞环境

该漏洞环境已经上传到 github 仓库上:https://github.com/dota-st/vulnEnv image-20221017113541029

首先在配置文件realm.ini中定义了用户账号密码以及对应角色权限 image-20221017113620512

ShiroConfig

@Configuration
public class ShiroConfig {

    @Bean
    public IniRealm getIniRealm(){
        return new IniRealm("classpath:realm.ini");
    }

    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
        return new DefaultWebSecurityManager(realm);
    }


    /*
     * anon:无需认证就可以访问
     * authc:必须认证才能访问
     * user:必须拥有记住我功能才能访问
     * perms:拥有某个资源的权限才能访问
     * role:拥有某个角色的权限才能访问
     * */
    @Bean
    ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(defaultWebSecurityManager);
        bean.setLoginUrl("/login.html");
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        map.put("/admin.html", "authc, roles[admin]");
        map.put("/user.html", "authc, roles[user]");
        map.put("/**", "anon");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }
}

UserController

@Controller
public class UserController {

    @PostMapping("/doLogin")
    public String doLoginPage(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(name="rememberme", defaultValue="") String rememberMe){
        if(ShiroUtil.login(username, password)){
            if(ShiroUtil.hasRole("admin")){
                return "redirect:/admin.html";
            } else if (ShiroUtil.hasRole("user")) {
                return "redirect:/user.html";
            }
        }
        return "redirect:/unauth.html";
    }

    @RequestMapping(value={"/"})
    public String helloPage() throws Exception {

        return "redirect:/login.html";
    }
}

漏洞分析

影响版本:shiro < 1.1.0

shiro 使用org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain()方法获取和调用执行的filter image-20221017161045663

在上图中可以看到,通过getPathWithinApplication()方法获取到我们传入的请求路径/./admin.html,接着通过filterChainManager.getChainNames()方法取出我们的配置

[/admin.html, /user.html, /**]

我们这里跟进一下getPathWithinApplication()方法 image-20221017161803921

继续跟进getPathWithinApplication()方法 image-20221017161912839

getRequestUri()方法中返回了/./admin.html,继续跟进getRequestUri()方法 image-20221017162105007

最后会 return 到decodeAndCleanUriString()方法,继续跟进该方法 image-20221017162648547

首先对 URL 进行 URL 解码,并对;进行截取,查了一下

decodeAndCleanUriString() 是 URL Decode 及针对 JBoss/Jetty 等中间件在 url 处添加 ;jsessionid 之类的字符串的适配,对 ; 进行了截取。

接下来getChain()方法往下走进行while循环,通过pathMatches()->pathMatcher.matches()方法进行匹配 image-20221017164449628

通过前面对请求处理的跟踪,可以发现在匹配之前没有对传进来的URL进行标准化路径处理,如果构造一下请求路径就有可能绕过权限校验。

回顾一下,我们的配置如下所示,设置admin.html文件只有amdin用户角色才能访问,同时设置/**anon

@Bean
    ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(defaultWebSecurityManager);
        bean.setLoginUrl("/login.html");
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        map.put("/admin.html", "authc, roles[admin]");
        map.put("/user.html", "authc, roles[user]");
        map.put("/**", "anon");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

访问admin.html,因为没有admin权限,校验失败故 302 跳转到了login.html image-20221017114715110

访问/./admin.html或者/aa/../admin.html,在while循环中,与前面的/admin.html/user.html匹配失败,进而进入了/**的匹配范围,成功访问到admin.html文件 image-20221017114807826