Apache shiro 权限绕过漏洞汇总

声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任 。
雷神众测拥有对此文章的修改和解释权 。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容 。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的 。
No.1
简述
前段时间太忙了,忙到很多东西,只是记录了笔记,没有成文,刚好最近阶段又出来了shiro权限绕过漏洞,因此本文将这三个权限绕过的洞进行对比,他们的编号分别是 CVE-2020-1957、CVE-2020-11989、CVE-2020-13933。
No.2
漏洞细节
1、CVE-2020-1957
原理

Apache shiro 权限绕过漏洞汇总

文章插图
首先在 admin 位置下断点,可以看到,我们网络请求,是先经过shiro 处理之后,再转发到springboot进行路由分发工作 。
Apache shiro 权限绕过漏洞汇总

文章插图
这里直接定位到 shiro处理url的方法位置:WebUtils# getPathWithinApplication
public static String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
// Normal case: URI contains context path.
String path = requestUri.substring(contextPath.length);
return (StringUtils.hasText(path) ? path : "/");
} else {
// Special case: rather unusual.
return requestUri;
}
}
实际上继续跟进 getRequestUri(request);这个方法,可以清楚的看到,实际上调用的是getRequestURI 方法来获取路由中的URI 请求 。
Apache shiro 权限绕过漏洞汇总

文章插图
这里的 URI就是我们传入的/xxx/..;/hello/aaaa,也就是说回到 getRequestUri(request);当中,会带着这个传入的URI进入decodeAndCleanUriString 进行处理 。
public static String getRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
if (uri == ) {
uri = request.getRequestURI;
}
return normalize(decodeAndCleanUriString(request, uri));
}
在 decodeAndCleanUriString方法中会根据我们的传入的URI中;进行截断处理,也就是说经过处理之后,返回的结果变成了/xxx/..
Apache shiro 权限绕过漏洞汇总

文章插图
而 normalize 方法就会对我们传入的path进行一些处理,从注释上,也能知道这部分代码处理了什么东西:
?替换\为/
?替换/./为/
?替换/../为/
?...
private static String normalize(String path, boolean replaceBackSlash) {
if (path == )
return ;
// Create a place for the normalized path
String normalized = path;
if (replaceBackSlash && normalized.indexOf('\') >= 0)
normalized = normalized.replace('\', '/');
if (normalized.equals("/."))
return "/";
// Add a leading "/" if necessary
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return ; // Trying to go outside our context
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Return the normalized path that we have completed
return (normalized);
}
而这里经过处理,我们的 URI 依然是/xxx/..,接着就会回到PathMatchingFilterChainResolver# getChain方法,进行权限匹配,我们的路径是/hello/**下需要进行权限认证,由于路径不匹配,所以权限校验自然过了 。
Apache shiro 权限绕过漏洞汇总


推荐阅读