CVE-2020-17523 shiro认证鉴权绕过复现

影响版本

  • Apache Shiro < 1.7.1

环境搭建

参考 https://github.com/jweny/shiro-cve-2020-17523

漏洞分析

代码作者设定:

  • 访问/login页面会提示please login
  • 访问/admin/**代表任意,网站会自动跳转至/login页面,表示用户未登录鉴权失败
  • 直接访问/admin会直接报错404,因为没有可以映射的url

代码在ShiroConfig中配置了shiro过滤器,可参考下图:

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("/admin/*", "authc"); 
    bean.setFilterChainDefinitionMap(map);
    return  bean;
}

漏洞利用:
访问/admin/%20会绕过shiro的鉴权认证,url会由spring处理跳转至admin页面:

通过比较shiro1.7.0和shiro1.7.1的源码:https://sourcegraph.com/github.com/apache/shiro/-/compare/shiro-root-1.7.0...shiro-root-1.7.1
可以发现主要改动的代码为core/src/main/java/org/apache/shiro/util/AntPathMatcher.java

直接在IDEA中搜索AntPatchMatcher类:

doMatch函数第一行打上断点,在多次步进后进入到/admin/ /admin/*的匹配阶段:

可以发现pathDirs中的空格已经丢失,所以这里的/admin/%20就直接变成了/admin
分析StringUtils.tokenizeToStringArray

//trimTokens=true,str=/admin/ ,delimiters="/",ignoreEmptyTokens=true
public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
        if (str == null) {
            return null;
        } else {
            StringTokenizer st = new StringTokenizer(str, delimiters); //用于分割字符串
            ArrayList tokens = new ArrayList();

            while(true) {
                String token;
                do {
                    if (!st.hasMoreTokens()) {  //判断是否有多余的分隔符
                        return toStringArray(tokens);
                    }

                    token = st.nextToken();  //获取当前位置到下一个分隔符之间的字符串
                    if (trimTokens) {   //是否对token进行特殊字符的删除,包括空格、换行符、\t等,由于这里为true,所以获取到空格时,空格被去掉了。
                        token = token.trim();
                    }
                } while(ignoreEmptyTokens && token.length() <= 0);

                tokens.add(token);
            }
        }
    }

所以这里的/admin/%20未匹配到自定义的shiro过滤器中的/admin/*,最后url直接映射到Spring的GetMapping里了,然后就直接返回了admin页面。

漏洞修复

升级到0.17.1版本,通过查看代码可以知道官方修复时将参数trimTokens 设置为false

posted @ 2021-02-04 17:29  flashine  阅读(1975)  评论(0编辑  收藏  举报