Apache shiro 权限绕过漏洞汇总( 二 )


文章插图
这里在提一嘴,可以看看 PathMatchingFilterChainResolver# getChain方法这一小段代码,这一段代码修复的是 Shiro-682 (https://issues.Apache.org/jira/browse/SHIRO-682),具体描述可以点入链接查看 。简单翻译一下就是在spring web下,通过请求 /resource/menus和/resource/menus/都是能够访问到资源的,但是shiro的路径正则只会匹配到/resource/menus,忽略了 /resource/menus/ ,所以这就绕过了 。

Apache shiro 权限绕过漏洞汇总

文章插图
Apache shiro 权限绕过漏洞汇总

文章插图
好了,这里提一下这个地方,再回到我们刚刚上面的情况里,由于我们传入的 URI/xxx/..与权限认证的URI/hello/**不匹配,绕过了权限验证之后,进入 springboot当中进行路由分发,而在spring当中UrlPathHelper# getPathWithinServletMapping 这个方法负责处理我们传入的URI:xxx/..;/hello/aaaa,结果是返回servletPath 。
public String getPathWithinServletMapping(HttpServletRequest request) {
String pathWithinApp = getPathWithinApplication(request);
String servletPath = getServletPath(request);
String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp);
String path;
【Apache shiro 权限绕过漏洞汇总】// If the app container sanitized the servletPath, check against the sanitized version
if (servletPath.contains(sanitizedPathWithinApp)) {
path = getRemainingPath(sanitizedPathWithinApp, servletPath, false);
}
else {
path = getRemainingPath(pathWithinApp, servletPath, false);
}
...
// Otherwise, use the full servlet path.
return servletPath;
}
}
看看 servletPath是怎么来的,这玩意的取值是通过request.getServletPath;获取到的,也就是说这里的结果是/hello/aaaa 。这里通过springboot进行分发,自然获取到后台接口内容,整个流程:
用户发起请求/xxx/..;/hello/aaaa----->shiro处理之后返回/xxx/..通过校验的----->springboot处理/xxx/..;/hello/aaaa返回/hello/aaaa,最后访问到需要权限校验的资源 。
public String getServletPath(HttpServletRequest request) {
String servletPath = (String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE);
if (servletPath == ) {
servletPath = request.getServletPath;
}
if (servletPath.length > 1 && servletPath.endsWith("/") && shouldRemoveTrailingServletPathSlash(request)) {
// On WebSphere, in non-compliant mode, for a "/foo/" case that would be "/foo"
// on all other servlet containers: removing trailing slash, proceeding with
// that remaining slash as final lookup path...
servletPath = servletPath.substring(0, servletPath.length - 1);
}
return servletPath;
}
Apache shiro 权限绕过漏洞汇总

文章插图
修复
shiro在1.5.2当中把之前的通过 getRequestURI获取URI的方式变成了getContextPath 、getServletPath 、getPathInfo 的组合 。
Apache shiro 权限绕过漏洞汇总

文章插图
这么处理之后自然变成了想要的东西 。
Apache shiro 权限绕过漏洞汇总

文章插图
2、CVE-2020-11989
原理
这里的 shiro拦截器需要变成map.put("/hello/*", "authc");,这里有两种poc,都是可以绕过
/hello/a%25%32%66a
/;/test/hello/aaa
我们知道在shiro中的WebUtils# getPathWithinApplication这里会处理我们传入的url,在 getRequestUri方法会调用decodeAndCleanUriString进行处理 。
public static String getRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
if (uri == ) {
uri = valueOrEmpty(request.getContextPath) + "/" +valueOrEmpty(request.getServletPath) +valueOrEmpty(request.getPathInfo);
}
return normalize(decodeAndCleanUriString(request, uri));
}
在 decodeAndCleanUriString当中会调用decodeRequestString针对URI进行一次URL解码 。
private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
uri = decodeRequestString(request, uri);
int semicolonIndex = uri.indexOf(';');
return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
}
public static String decodeRequestString(HttpServletRequest request, String source) {
String enc = determineEncoding(request);
try {
return URLDecoder.decode(source, enc);
} catch (UnsupportedEncodingException ex) {
if (log.isWarnEnabled) {


推荐阅读