序
前段时间跟完了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
利用条件
- shiro<=1.5.1
- spring版本最好为1.x.x
原理概述
这个漏洞的是由于shiro和spring处理的请求路径不一致造成的,shiro在处理请求时将;
后面的路径都忽略,然后取得对应的过滤器进行拦截。spring处理请求时则不会将;
后面的路径忽略,并且会解析..
。
在1.5.2版本的修复中可以发现,shiro将处理路径的代码与spring进行了统一。
payload
/fsdf;/../hello/1111
/fsdf/..;/a;aaa;a/..;/hello/1
注意事项
复现时注意springboot版本,低版本会对路径中的..进行解析处理,高版本则不会。
复现时尽量使用bp抓包更改路径。比如如下payload
/fsdf;/../hello/1231
直接使用火狐请求这个路径无法绕过,而使用bp则可以。原因是浏览器自作聪明的帮我们解析了
..
导致payload无效。使用火狐发送上面的payload,bp抓包得到的是。可以发现,
..
被浏览器解析了。直接在bp改包即可成功
CVE-2020-11989
利用条件
- shiro<=1.5.2
- 方式1需要接口接收String类型的参数
- 方式1要求路径限制为
*
,不能是**
- 方式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
利用条件
- shiro<=1.5.3
- 路径限制为
*
,不能是**
原理概述
首先getPathWithinApplication会先把/hello/%3b123
处理成/hello/
(即删除;
后面的内容)
getChain函数在处理路径时,会将末尾的/
删除,而/hello/*
这种通配符不能匹配/hello
,就导致了绕过。
如果不将;
进行编码,spring在处理时会把;
后面的内容忽略,得到的是/hello/
,无法与/hello/*
的控制器方法匹配
注意点
前面讨论CVE-2020-1957时我们说spring处理请求时则不会将;
后面的路径忽略,并且会解析..
,而这里我们又说spring会将;
后面的路径忽略,下面具体看一下源码究竟是怎么回事。
在spring解析路径准备找controller处理请求时,会调用UrlPathHelper:getPathWithinServletMapping
。只需要搞明白这个函数上面的问题就能理解了。这个函数的作用可以简单的理解成返回请求路径。
看看CVE-2020-1957,我们发送payload/fsdf;/../hello/1111
断点停在UrlPathHelper:getPathWithinServletMapping
,这个函数的返回的是servletPath,它是通过this.getServletPath(request);
获取的
这个getServletPath(request)
底层就是调用了servlet的实现得到请求路径,会处理..
和;
,得到的最终结果是/hello/1111
。
再看看正在分析的CVE-2020-13933,如果不将;
进行编码,发送payload/hello/;123
,UrlPathHelper:getPathWithinServletMapping
获取到的路径就是是/hello/
,将通过这个路径去找对应的Controller方法。
总结一下就是,如果;
和..
同时出现,将不会忽略掉;
后面的内容,而是先解析..
。如果单独出现;
,则会忽略它后面的内容。
payload
/hello/%3b123
CVE-2020-17523
利用条件
- shiro<=1.6.0
- 方式二的利用条件是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/
参考文章