Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why do all the serialized payloads contain java.lang.Override? #75

Closed
SivaDotRender opened this issue Sep 25, 2017 · 3 comments
Closed

Comments

@SivaDotRender
Copy link

SivaDotRender commented Sep 25, 2017

I am trying attempting to use ysoserial to generate a Groovy1 payload against an old version of elasticsearch. The payload fails to deserialize due to the presence of java.lang.Override. Specifically, elastic search seems to call the following function when resolving classes contained within a serialized stream:

protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { int type = read(); if (type < 0) { throw new EOFException(); } switch (type) { case ThrowableObjectOutputStream.TYPE_EXCEPTION: return ObjectStreamClass.lookup(Exception.class); case ThrowableObjectOutputStream.TYPE_STACKTRACEELEMENT: return ObjectStreamClass.lookup(StackTraceElement.class); case ThrowableObjectOutputStream.TYPE_FAT_DESCRIPTOR: return super.readClassDescriptor(); case ThrowableObjectOutputStream.TYPE_THIN_DESCRIPTOR: String className = readUTF(); Class<?> clazz = loadClass(className); return ObjectStreamClass.lookup(clazz); default: throw new StreamCorruptedException( "Unexpected class descriptor type: " + type); } }

ObjectStreamClass.lookup(clazz) returns null when clazz == "java.lang.Override". I am not entirely sure what the purpose of java.lang.Override is in the serialized object but is there any way of generating payloads which do not contain this class?

Thanks in advance for the help.

@frohoff
Copy link
Owner

frohoff commented Sep 25, 2017

The Groovy1 payload and any other that depends on an AnnotationInvocationHandler instance will require some annotation class to be present in the stream to work properly. java.lang.Override was arbitrary chosen because it was a parameter-less annotation class that was present in the JRE itself since annotations were introduced in Java 1.5.

I don't have specific experience with elasticsearch, but looking at some source code it looks like it uses a slightly modified deserialization stream format and behavior via ThrowableObjectOutputStream and ThrowableObjectInputStream that:

  • omits the STREAM_MAGIC (0xACED) bytes in writeStreamHeader()/readStreamHeader()
  • prefixes class descriptions with additional TYPE_EXCEPTION (0x2), TYPE_STACKTRACE_ELEMENT (0x3), TYPE_FAT_DESCRIPTOR (0x0), TYPE_THIN_DESCRIPTOR (0x1) bytes in writeClassDescriptor()/readClassDescriptor()
  • has a custom loadClass() method that may load a custom classloader with fewer classes available

In this scenario, it seems likely that the last of these customizations may be getting in the way of it working, but it's hard to say for sure without more information about which path it's following through the readClassDescriptor() and loadClass() and what it's classpath environment looks like.

It may also be worth asking in the gitter chat to see if anyone else has come across this specific vector and/or issue before.

@SivaDotRender
Copy link
Author

Thank you for the reply @frohoff. I will try and look into the issue further with your feedback in mind.

@frohoff
Copy link
Owner

frohoff commented Oct 2, 2017

Closing after resolution via gitter chat.

@frohoff frohoff closed this as completed Oct 2, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants