Spring4Shell: Security Analysis of the latest Java RCE '0-day' vulnerabilities in Spring
Sometimes vulnerabilities come from trying to be too generic/handle all the possibilities, this is one of those situations. What you have the Spring Framework letting users write simple Java classes with fields, getters/setters and setting those up as models for a particular endpoint. Spring will then try to map request parameters to class fields and set them appropriately, to do this it uses the java.beans.Introspection
class which uses a bit of Java magic to look at the internal java representation for an arbitrary object and determine what fields have getters/setters and can be modified. It can also recurse into the nested objects.
While the fields you’d expect do come back, one unexpected property though is class
. This is because any plain object/class in Java automatically inherits from Object.Class
which has the getClass()
method. Form there you can go on down the class tree, potentially leading to the ability to set some important and sensitive classes.
There was a 2010 attack taking advantage of this same issue, where the exploit targeted class.classLoader.URLs
to trick the system into adding a remote address to the paths the class loader would look for classes in. This was patched by checking if the property name was classLoader
and it was in the Class
class.
This worked for awhile, it appears a few years later, they also blocked the “protectionDomain” field in this commit. Though I’m not sure about the details on that attack (if any).
So effectively the patches have been through blocklisting whatever means someone found to exploit it. That’s true for Spring4Shell too, Java 9 introduced Modules and with that the module
field, which itself also exposed classLoader
but as the module
isn’t the Class
class it bypasses the existing checks. Though, Java 9 doesn’t load remote JARs anymore, so the old exploit couldn’t be revived.
Instead, the exploitation takes a more round about way, through class.module.classLoader.resources.context.parent.pipeline.first
which reminds me a lot of Python sandbox escaping where you work your way to the base python class then try and access different fields working your way to arbitrary classes. In this case it is working it way to some of Tomcat’s logging properties. A full exploit would use multiple requests to set several of these properties resulting in writting a shell to the server as a “log”.
class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20[url safe JSP file here]%20%25%7Bsuffix%7Di
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
While this particular exploit requires Tomcat, it is likely other fields could be abused in other situations to gain code execution.
The patch once again is block listing but they are a bit more comprehensive this time. Only allowing access to name
from within Class
and denying access to the ClassLoader
and ProtectionDomain
classes all together.