The ysoserial makes Java deserialization vulnerabilities easy to exploit and Stephen Breen demonstrated the majority of Java web servers are vulnerable. I thought it would be interesting to see how common deserialization is in open source Java projects.
I developed a script to search and sort the most popular repositories on GitHub by language. Searching the 200 most popular Java repositories for uses of new ObjectInputStream
showed:
16 percent of Java repositories explicitly create and use an ObjectInputStream. Using an ObjectInputStream doesn’t mean the program is vulnerable - a vulnerability exists when the ObjectInputStream processes data from an untrusted source and the class path contains a “gadget chain”.
The majority of the above projects, especially Android projects, use serialization to persist an object to disk and restore it later. If an attacker can modify files then this bug is unlikely to elevate their privileges. But there is a few projects that accept data remotely and deserialize it! Lets explore attempting to exploit one of them.
Note: The real percentage of Java projects using serialization is likely much higher because popular frameworks internally use serialization.
When writing this blog post Gradle was the 101st most popular Java project on GitHub with more than 3500 stars. This project is an extremely popular build system for Java and is the standard build system for Android.
Gradle deserializes data in the ObjectSocketWrapper class. This class is used in the jetty subproject here and the ui subproject here and here. Both of these plugins open a socket and wait for a client to connect and send serialized data.
The ui subproject is easy to work with, it can be launched by executing ./gradlew –gui.
An ephemeral port opened and is listening for connections on all interfaces.
To confirm the vulnerability lets send a serialized object and confirm the program attempted to deserialized it. I built the project in Intellij Idea and attached breakpoints on the socket accept and readObject method. Sending an arbitrary payload from ysoserial to the socket:
Stepping through the readObject method confirms the program attempted to deserialize the CommonsBeanutils1 payload
At this point we can consider the ui subproject and jetty subproject vulnerable. Successful exploitation depends on finding a gadget chain in the projects classpath.
Each projects dependencies can be listed using the gradle task dependencies and executing ysoserial with no arguments lists the known gadget chains. Cross checking these two lists:
Library | Vulnerable version | ui-subproject version | Exploitable |
---|---|---|---|
BeanShell1 | org.beanshell:bsh:2.0b5 | n/a | N |
C3P0 | com.mchange:c3p0:0.9.5.2, com.mchange:mchange-commons-java:0.2.11 | n/a | N |
CommonsBeanutils1 | commons-beanutils:commons-beanutils:1.9.2, commons-collections:commons-collections:3.1, commons-logging:commons-logging:1.2 | n/a | N |
CommonsCollections1 | commons-collections:commons-collections:3.1 | Commons collections 3.2.2 | N |
CommonsCollections2 | org.apache.commons:commons-collections4:4.0 | Commons collections 3.2.2 | N |
commonscollections3 | commons-collections:commons-collections:3.1 | commons collections 3.2.2 | n |
commonscollections4 | org.apache.commons:commons-collections4:4.0 | commons collections 3.2.2 | n |
commonscollections5 | commons-collections:commons-collections:3.1 | commons collections 3.2.2 | n |
fileupload1 | commons-fileupload:commons-fileupload:1.3.1, commons-io:commons-io:2.4 | n/a | n |
groovy1 | org.codehaus.groovy:groovy:2.3.9 | groovy 2.4.4 | n |
jdk7u21 | jdk7u21 | ? | |
jython1 | org.python:jython-standalone:2.5.2 | n/a | n |
spring1 | org.springframework:spring-core:4.1.4.release, org.springframework:spring-beans:4.1.4.release | n/a | n |
Spring2 | org.springframework:spring-core:4.1.4.RELEASE, org.springframework:spring-aop:4.1.4.RELEASE, aopalliance:aopalliance:1.0, commons-logging:commons-logging:1.2 | n/a | N |
The projects dependencies are all non-vulnerable versions. Downgrading to Gradle 2.12 and checking the library versions again shows commons-collections 3.2.1. The commons-collections5 payload in ysoserial successful executes an arbitary commands.
Looking through the Gradle release notes this vulnerability was not mentioned, I suspect the developers were unaware of it and were just upgrading their libraries. I’ve requested CVE-2016-6199 to track this vulnerability.
If you are running Gradle 2.12 or earlier you should upgrade. While this post details exploiting the UI subproject, the Jetty subproject is similarly vulnerable. The searching script found more projects that appear vulnerable. It might also be interesting to identify and search for framework APIs that wrap serialization.