CVE-2022-41923
漏洞通告
在某些使用 Grails Spring Security Core (GSSC) 插件的 Grails 框架应用程序中,将根据满足捐赠者端点的授权要求来授予对目标端点的访问权限,这可能会导致权限升级攻击。
影响版本
如果您无法升级到插件的修补版本,GSSC-CVE-2022-41923存储库包含 GSSC 插件版本 2.x 到 5.x 的解决方法。该解决方法对于 2.x 版本尤其重要,因为GSSC 插件 2.x 版本没有可用的补丁。
POC
当权限设置为『普通用户不可以访问http:..127.0.0.1:8080.hello.user.admin』时,可通过访问『http:..127.0.0.1:8080.hello.user;.admin』进行绕过
漏洞分析
在github中找到对应代码库,并切换到3.x版本。
漏洞核心函数为groovy.grails.plugin.springsecurity.web.access.intercept .AbstractFilterInvocationDefinition.groovy#calculateUri代码如下
protected String calculateUri(HttpServletRequest request) {
String url = request.requestURI.substring(request.contextPath.length())
int semicolonIndex = url.indexOf(';')
semicolonIndex == -1 ? url : url.substring(0, semicolonIndex)
}
可以看到,在处理url时,只提取了;前的部分。
向上追踪,看谁调了calculateUri
protected String determineUrl(FilterInvocation filterInvocation) {
lowercaseAndStripQuerystring calculateUri(filterInvocation.httpRequest)
}
Collection<ConfigAttribute> getAttributes(object) throws IllegalArgumentException {
assert object, 'Object must be a FilterInvocation'
assert supports(object.getClass()), 'Object must be a FilterInvocation'
FilterInvocation filterInvocation = (FilterInvocation)object
String url = determineUrl(filterInvocation)
if (url == ERROR404) {
return ALLOW404
}
log.trace 'getAttributes(): url is {} for FilterInvocation {}', url, filterInvocation
Collection<ConfigAttribute> configAttributes = findConfigAttributes(url, filterInvocation.request.method)
if (rejectIfNoRule && !configAttributes) {
log.trace 'Returning DENY, rejectIfNoRule is true and no ConfigAttributes'
// return something that cannot be valid this will cause the voters to abstain or deny
return DENY
}
log.trace 'ConfigAttributes are {}', configAttributes
configAttributes
}
// GrailsWebInvocationPrivilegeEvaluator#isAllowed
@Override
boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
assert uri, 'uri parameter is required'
if (contextPath == null) {
contextPath = '/ctxpath'
}
FilterInvocation fi = createFilterInvocation(contextPath, uri, method)
log.trace "isAllowed: contextPath '{}' uri '{}' method '{}' Authentication {} FilterInvocation {}",
contextPath, uri, method, authentication, fi
Collection<ConfigAttribute> attrs = interceptor.obtainSecurityMetadataSource().getAttributes(fi)
if (attrs == null) {
log.trace 'No ConfigAttributes found'
return !interceptor.rejectPublicInvocations
}
if (!authentication) {
log.trace 'Not authenticated'
return false
}
try {
interceptor.accessDecisionManager.decide authentication, fi, attrs
log.trace "{} allowed for {}", fi, authentication
true
}
catch (AccessDeniedException unauthorized) {
if (log.debugEnabled) {
log.debug "$fi denied for $authentication", GrailsUtil.deepSanitize(unauthorized)
}
false
}
}
所以这时可以成功绕过权限检查