前言

近期shiro多次对权限绕过问题进行了修复,在此对相关漏洞进行学习分析,了解整个修复过程中的安全对抗策略。
本地环境:idea + shirodemo 项目代码

CVE-2020-1957

版本<1.5.0

有人在github上提交pr表示可以通过在末尾增加/,绕过shiro的权限认证。 随后官方对这个pr进行了合并,发布了版本1.5.0。
使用修复前的最后一个版本1.4.2进行测试,配置的路径拦截规则如下:

map.put(“/doLogin”, “anon”);
map.put(“/hello/*”, “authc”);
bean.setFilterChainDefinitionMap(map);

顺利通过 /hello/a/ 绕过权限限制

调试看看漏洞现场的具体情况,根据补丁信息把断点打在PathMatchingFilter.pathsMatch和PathMatchingFilterChainResolver.getChain函数。
程序运行后停在getChain函数中,它调用getPathWithinApplication获取URI路径,然后遍历filterChains逐个进行匹配pathMatches

实际的匹配逻辑在方法AntPathMatcher.doMatch,先将patternpath解析成字符串数组,此时会忽略多余的分隔符/。然后逐项进行匹配,存在**则会跳出循环并且倒序再匹配,在matchString中对*?进行匹配处理。
总结一下ant匹配语法:

?:匹配一个字符
:匹配零个或多个字符串
*
:匹配路径中的零个或多个路径

正向匹配完所有字符数组,然后会校验pattern和path的末尾的斜线是不是一致。这里校验失败导致绕过了校验

1.5.0补丁

在调用pathMatches进行匹配查找之前把path和pattern最后的/删除

1.5.0补丁绕过

由于tomcat的特性,可以通过;来绕过。访问/hello;/aaa/,此时getPathWithinApplication获取到的路径为/hello,导致绕过。

网传的另外一个PoC /fdsf;/../hello/1,但我在本地复现报404错误

1.5.2补丁

针对1.5.0的绕过,官方发布了1.5.2版本进行修复。在WebUtils.getRequestUri函数中,原先从request.getRequestURI()获取路径,现在拼接getContextPathgetServletPathgetPathInfo三部分。

至此CVE-2020-1957的生命结束,但新一轮的抗争由此开始。

CVE-2020-11989

再仔细看看WebUtils.getRequestUri方法,其中会调用decodeAndCleanUriStringnormalize对uri进行处理。
decodeAndCleanUriString先会对uri进行url解码,然后如果存在;则截取前半部分字符串。而normalize则是对\///.//../进行处理。

根据decodeAndCleanUriString就能构造出新的绕过 /hello/%253ba,shiro解析出来的URI是/hello/,与pattern /hello/*匹配不上。
除了通过截断URI还可以通过插入路径分隔符让*匹配不上,使用 /hello/a%252fa,shiro解析到的/hello/a/a 同样也匹配不到 /hello/*

1.5.3补丁
直接拼接getServletPath和getPathInfo,不再进行解码操作。removeSemicolon函数用来截取分号;

把1.5.2中对WebUtils.getRequestUri的改动进行了还原,并且标记为Deprecated。getServletPath和getPathInfo只是进行了封装,本质还是从request对象中获取数据

CVE-2020-13933

咋一看补丁没什么问题,但仔细想想这里却别有洞天。在getServletPathgetPathInfo之前,tomcat已经对;进行了normalize处理,这里的;其实是url中的%3b,不太明白开发者为什么要在这里处理;。可以继续用%3b截断path来绕过pattern校验,PoC:/hello/%3ba
这个PoC只影响1.5.0到1.5.3版本,但不影响最开始的1.4.2版本。因为1.5.0补丁引入的代码会将path和pattern最后的/删除,导致pathMatches函数中pattern:/hello/* 匹配不到path: /hello/了,中间的多次绕过都利用了这一点。

终局之战

1.6.0版本的修复方式有点狠,新增InvalidRequestFilter检查getRequestURI()中是否存在黑名单元素(";", "%3b", "%3B" "\\", "%5c", "%5C" )以及非打印字符。

修复方式比较有效,但也引入了一个bug。原本客户端没设置cookie的情况下,重定向到登录页时会带参数 /login;jsessionid=xxx,但目前302后会导致请求400 Bad Request。
shiro权限绕过的问题也许没有真正落幕,期待下一次绕过的出现。

参考链接
https://issues.apache.org/jira/browse/SHIRO-682
https://segmentfault.com/a/1190000019440231
https://www.freebuf.com/vuls/231909.html
https://xlab.tencent.com/cn/2020/06/30/xlab-20-002/




Published with Hexo and Theme by Kael
X