CVE-2022-41923 漏洞分析

247 阅读1分钟

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
    }
  }

所以这时可以成功绕过权限检查