Hacker News new | ask | show | jobs
by WatchDog 1544 days ago
There is a lot of bad information out there about this issue.

What I have gathered so far, is that this is actually a real problem, but it may not affect most configurations.

This[0] seems to be the original vulnerability analysis, and this is the example vulnerable app[1].

The main issue seems to be, that since java 9, WebDataBinder can be abused to access the classloader via the "class.module.classloader", you might think that "class.classloader" would work, but it's explicitly filtered out[2], it seems they need to add some filtering for module, as well.

The proof of concept, then access the "AccessLogValve" class via "class.classLoader.resources.context.parent.pipeline.first", which is only accessible if the application is running using a "WeappClassLoaderBase", it then configures the logger, to output an arbitrary JSP file to the webapp root directory, which can then be used to get a shell.

It looks like this issue is only exploitable if your app is deployed as a war file.

[0]: https://github.com/TheGejr/SpringShell/blob/master/Vulnerabi...

[1]: https://github.com/fengguangbin/spring-rce-war

[2]: https://github.com/spring-projects/spring-framework/blob/mai...

4 comments

Ahh, your comment is the first one that made it clear why this is only in 9 and later, because it was actually "introduced" by the introduction of modules in Java 9. That added https://docs.oracle.com/javase/9/docs/api/java/lang/Class.ht... to java.lang.Class.

It looks like the Spring code, when written, did properly filter out existing unsafe methods in java.lang.Class deliberately. Obviously not in a defensive enough way to avoid this, but adding methods to java.lang.Class is a very rare event.

> output an arbitrary JSP file

So i appreciate that this is only an example of a gadget, and there are others that could be invoked in the same way, but ...

> to the webapp root directory

This is only possible if the application is running from an exploded WAR. That can happen if the developer deploys an exploded WAR - normal in development, extremely strange in production - or if the application server explodes the WAR to run it. I know it used to be standard for application servers to do that, but my understanding was that they stopped doing this 5 - 10 years ago, and now run applications directly from the WAR file. That said, i am certainly not intimately familiar with all extant application servers, or what versions are in use - perhaps there are plenty of deployments that still do this.

I always argued for deploying the app as one user, then executing it as another, which didn't have write access to the deployment, specifically to avoid this class of problem, but nobody ever bothers to do that!

The default config for tomcat is to explode the WAR, even in the most recent version.
Right, war files are still a thing for people stuck on older architectures involving things like tomcat or jboss. The venn diagram of doing that with current JDKs and modern spring would be pretty narrow. Most people would just use spring boot, which runs as a simple server that starts via a main function. Usually jetty or tomcat in embedded mode. If you really wanted to, I guess you could pack it up as a war file and deploy that. But I've never seen anyone do that with Spring Boot. The last time I worked with tomcat was about 10 years ago before either Spring Boot or Java 8 were a thing.

Nasty issue though and they should close it off.

> If you really wanted to, I guess you could pack it up as a war file and deploy that. But I've never seen anyone do that with Spring Boot.

I have actually seen this done. It was extremely underwhelming and provided no tangible benefits versus just having an executable .jar file instead. The filesize difference was negligible and being able to update Tomcat versions separately wasn't all that useful. In the end, the project was migrated over to running as a .jar instead.

Then again, i've also seen projects where Jetty is used locally and .war with Tomcat is used when deployed, which was an inconsistent mess.

Overall, Tomcat is pretty cool but the ease of use with Spring Boot running Tomcat or anything else in embedded mode is really nice.

The main benefit is updating the webapps w/o restarting the server, itself. Spring, itself, is a rather slow due to on the fly bean resolution/binding/etc. though, so the benefits are not that pronounced.
> The main benefit is updating the webapps w/o restarting the server, itself.

I've never had this work properly in the long term, to be honest. Restarts with the Jenkins plugin would randomly freeze and fail or there would be memory leaks after too many restarts, or weird errors about it not being possible to properly clear up the resources from previously exploded/extracted .war archives.

Though i might have just been unlucky, who knows.

There are many things that must go right. Threads being the primary one - don't start threads, pretty much anything that can start threads (outside the webapp) have to guard for the CCL and the thread group at the very least.

The entire app must have a clear start/stop lifecycle correctly implemented. Static registrations in non-webapp services must be removed, and/or those services must use weak references.

The list is quite long. (Source - I have done my fair share of middleware and know tomcat source quite well)

While this is possible, it takes ages for an application to gracefully shutdown so any time you save not having to start up a new server is lost. And then you still have classloader, memory and thread leaks since you can't really prove they are absent unless you have 100% test coverage + load testing on every possible code path.

Modern Java webservers (even 'enterprise' containers like JBoss etc) start up so quickly now there's not much to gain by not restarting them.

If you can access the classloader that's pretty bad, it's likely people will find other gadgets.

It's insane to me though that class.* isn't completely disallowed. What is the legitimate use case for deserializing allowing web requests to call setters in the reflection API?

Also, agree it is impressive to me how much bad information I've seen.

Yea it didn't help that this was posted a bit after https://spring.io/blog/2022/03/29/cve-report-published-for-s... and that the original article mentioned a commit on the class `SerializationUtils` which in the end has no connection to this.

I believe accessing the `class` object here is a mistake. You can see my analysis here where I trace the POC https://news.ycombinator.com/item?id=30862953 but like you said, there are other problematic code paths for sure with this.