Last active
November 11, 2015 02:51
-
-
Save takawitter/20d1a88b497d596df16b to your computer and use it in GitHub Desktop.
Limit class reference when deserializing object by using custom class loader.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import java.io.ObjectStreamClass; | |
import java.net.URL; | |
import java.net.URLClassLoader; | |
import java.nio.file.Paths; | |
import java.util.HashMap; | |
import java.util.Map; | |
import org.apache.commons.collections4.functors.ChainedTransformer; | |
import org.apache.commons.collections4.functors.ConstantTransformer; | |
import org.apache.commons.collections4.functors.InvokerTransformer; | |
import org.apache.commons.collections4.map.LazyMap; | |
public class LimitClassReferenceWhenDeserializingObject { | |
@SuppressWarnings({ "rawtypes", "unchecked" }) | |
public static void main(String[] args) throws Throwable{ | |
Map<String, String> map = LazyMap.lazyMap(new HashMap<>(), new ChainedTransformer( | |
new ConstantTransformer(Runtime.class), | |
new InvokerTransformer( | |
"getMethod", | |
new Class[] { String.class, Class[].class }, | |
new Object[] { "getRuntime", new Class[0] }), | |
new InvokerTransformer( | |
"invoke", | |
new Class[]{ Object.class, Object[].class }, | |
new Object[]{ null, new Object[0] }), | |
new InvokerTransformer( | |
"exec", | |
new Class[]{ String.class }, | |
new Object[]{"touch hello.txt"}), | |
new ConstantTransformer("hello") | |
)); | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
ObjectOutputStream oos = new ObjectOutputStream(baos); | |
oos.writeObject(map); | |
oos.flush(); | |
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())){ | |
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException ,ClassNotFoundException { | |
System.out.println("resolve class: " + desc.getName()); | |
if(desc.getName().startsWith("[")) return super.resolveClass(desc); | |
ClassLoader cl = new URLClassLoader( | |
new URL[]{Paths.get("bin/").toUri().toURL()} | |
, null | |
){ | |
protected java.lang.Class<?> findClass(String name) throws ClassNotFoundException { | |
System.out.println("find class: " + name); | |
return super.findClass(name); | |
} | |
}; | |
return cl.loadClass(desc.getName()); | |
} | |
}; | |
System.out.println(((Map<String, Object>)ois.readObject()).get("hello")); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resolve class: org.apache.commons.collections4.map.LazyMap | |
find class: org.apache.commons.collections4.map.LazyMap | |
resolve class: org.apache.commons.collections4.functors.ChainedTransformer | |
find class: org.apache.commons.collections4.functors.ChainedTransformer | |
resolve class: [Lorg.apache.commons.collections4.Transformer; | |
resolve class: org.apache.commons.collections4.functors.ConstantTransformer | |
find class: org.apache.commons.collections4.functors.ConstantTransformer | |
resolve class: java.lang.Runtime | |
resolve class: org.apache.commons.collections4.functors.InvokerTransformer | |
find class: org.apache.commons.collections4.functors.InvokerTransformer | |
resolve class: [Ljava.lang.Object; | |
resolve class: [Ljava.lang.Class; | |
resolve class: java.lang.String | |
resolve class: java.lang.Object | |
resolve class: java.util.HashMap | |
Exception in thread "main" java.lang.ClassNotFoundException: org.apache.commons.collections4.map.LazyMap | |
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) | |
at cpiso.LimitedClassReference$1$1.findClass(LimitedClassReference.java:53) | |
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) | |
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) | |
at cpiso.LimitedClassReference$1.resolveClass(LimitedClassReference.java:60) | |
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613) | |
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) | |
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) | |
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) | |
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) | |
at cpiso.LimitedClassReference.main(LimitedClassReference.java:63) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Comment out line 48, for deserialization volnerability to work. Even you commented out 48, you can filter classes to be loaded at line 51.