0%

shiro权限绕过

前段时间跟完了shiro550和721两个经典的反序列化漏洞,想把shiro学的更全面一些,于是接着来跟一下shiro的权限绕过。本文是参考xq17师傅的文章进行复现,仅做一些补充和个人记录。以下cve如无特殊说明,均是在springboot1.5.22.RELEASE版本下进行。

<=1.4.2

原理概述

/hello/*的拦截规则无法拦截/hello/1/,而/hello/1/能够获取/hello/1一样的资源

payload

/hello/1为受限资源

/hello/1/

CVE-2020-1957

利用条件

  1. shiro<=1.5.1
  2. spring版本最好为1.x.x

原理概述

这个漏洞的是由于shiro和spring处理的请求路径不一致造成的,shiro在处理请求时将;后面的路径都忽略,然后取得对应的过滤器进行拦截。spring处理请求时则不会将;后面的路径忽略,并且会解析..

在1.5.2版本的修复中可以发现,shiro将处理路径的代码与spring进行了统一。

payload

/fsdf;/../hello/1111
/fsdf/..;/a;aaa;a/..;/hello/1

注意事项

  1. 复现时注意springboot版本,低版本会对路径中的..进行解析处理,高版本则不会。

  2. 复现时尽量使用bp抓包更改路径。比如如下payload

    /fsdf;/../hello/1231
    

    直接使用火狐请求这个路径无法绕过,而使用bp则可以。原因是浏览器自作聪明的帮我们解析了..导致payload无效。

    使用火狐发送上面的payload,bp抓包得到的是。可以发现,..被浏览器解析了。

    image-20210817124811289

    直接在bp改包即可成功

    image-20210817124758774

CVE-2020-11989

利用条件

  1. shiro<=1.5.2
  2. 方式1需要接口接收String类型的参数
  3. 方式1要求路径限制为*,不能是**
  4. 方式2需要项目配置context-path

原理概述

方式一是由于shiro在处理请求路径时会双url解码,比如/shiro/hello/luanxie%25%32%661 被解码成了/shiro/hello/luanxie/1,这个路径不会被拦截。而spring在解析时仅进行了一次url解码,得到的就是/shiro/hello/luanxie%2f1,实现绕过。

在说方式二之前,与1.5.1做一个衔接。为了修复1.5.1的漏洞,shiro将url的处理方式与spring进行了统一,改成了如下方式。但是在request.getContextPath()中出现了问题,这个函数的作用就是得到context-path,但是在获取过程中没有做特殊处理,传入/;/shiro/hello/hi,直接返回了/;/shiro。接下来的原因就跟1.5.1的漏洞相同了,;后的路径直接被shiro截断,导致了绕过。

public static String getRequestUri(HttpServletRequest request) {
    String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
    if (uri == null) {
    uri = valueOrEmpty(request.getContextPath()) + "/" + valueOrEmpty(request.getServletPath()) + valueOrEmpty(request.getPathInfo());
    }

    return normalize(decodeAndCleanUriString(request, uri));
}

payload

方式一

#shiro是context-path,没有设置可以不写。这里为了和方式二共用一个环境所以设置了
/shiro/hello/luanxie%25%32%661 

方式二

/;/shiro/hello/hi

CVE-2020-13933

利用条件

  1. shiro<=1.5.3
  2. 路径限制为*,不能是**

原理概述

首先getPathWithinApplication会先把/hello/%3b123处理成/hello/(即删除;后面的内容)

getChain函数在处理路径时,会将末尾的/删除,而/hello/*这种通配符不能匹配/hello,就导致了绕过。

image-20210817151631955

如果不将;进行编码,spring在处理时会把;后面的内容忽略,得到的是/hello/,无法与/hello/*的控制器方法匹配

image-20210817154532477

注意点

前面讨论CVE-2020-1957时我们说spring处理请求时则不会将;后面的路径忽略,并且会解析..,而这里我们又说spring会将;后面的路径忽略,下面具体看一下源码究竟是怎么回事。

在spring解析路径准备找controller处理请求时,会调用UrlPathHelper:getPathWithinServletMapping。只需要搞明白这个函数上面的问题就能理解了。这个函数的作用可以简单的理解成返回请求路径。

image-20210817161056714

看看CVE-2020-1957,我们发送payload/fsdf;/../hello/1111

断点停在UrlPathHelper:getPathWithinServletMapping,这个函数的返回的是servletPath,它是通过this.getServletPath(request);获取的

image-20210817162855954

这个getServletPath(request)底层就是调用了servlet的实现得到请求路径,会处理..;,得到的最终结果是/hello/1111

image-20210817162530415

再看看正在分析的CVE-2020-13933,如果不将;进行编码,发送payload/hello/;123UrlPathHelper:getPathWithinServletMapping获取到的路径就是是/hello/,将通过这个路径去找对应的Controller方法。

总结一下就是,如果;..同时出现,将不会忽略掉;后面的内容,而是先解析..。如果单独出现;,则会忽略它后面的内容。

payload

/hello/%3b123

CVE-2020-17523

利用条件

  1. shiro<=1.6.0
  2. 方式二的利用条件是springboot开启了全路径模式,springboot>=2.3.0RELEASE默认开启了该模式

原理概述

方式一是利用了shiro在拆分请求路径时的问题,/hello/{空格}被拆分成了hello,空格被忽略了。导致/hello/*无法匹配/hello。而spring却能正确拆分/hello/{空格},进而正确解析该请求,从而实现了绕过。

方式二是由于shiro在处理请求路径时,调用getServletPath(),它会解析...使得如下payload发生变化,然后末尾的/又会被删除,导致/hello/*无法匹配/hello,实现绕过。

/hello/%2e  ->  /hello/
/hello/%2e/  ->  /hello/
/hello/%2e%2e/  ->  /

payload

方式一

/hello/%20

方式二

/hello/%2e
/hello/%2e/
/hello/%2e%2e/

参考文章

Shiro 权限绕过的历史线(上)

Shiro权限绕过漏洞分析(CVE-2020-1957)