-
Notifications
You must be signed in to change notification settings - Fork 22
Disable dynamic class loading and Java serialization by default #14
Comments
@bgloeckle I'd like to get a second opinion on this before I hack it. Thoughts? The thought is, absent serialization and loading of class names, the Catalyst serialized effectively whitelists classes by requiring registration of serializable types either through the |
I think whitelisting the classes is the usual fix for this problem, so that should be good to go. Though I don't fully understand what you mean with "Serializing class names" - do you mean the #readByClass and #writeByClass methods in Serializer? I think they're not the problem, but the problem is the ObjectInputStream used in #readBySerializable. The data that is written and read by the "byClass" methods could be crafted by an attacker (to match a whitelisted class name), but the actual Serializable that is deserialized could be harmful and the attack would have succeeded even before ObjectInputStream#readObject returns. I think you should subclass ObjectInputStream here and overwrite at least the #resolveClass method. That should then be enough to filter the valid class names: Just throw a ClassNotFoundException if the class is not on the whitelist. You might also want to overwrite the #resolveProxyClass method and just throw ClassNotFoundException always - as Proxies should never be deserialized in copycat anyway AFAIK. |
Actually, you're right. I was thinking readByClass did not care if the class name was whitelisted, but that's not the case. A TypeSerializer still has to be registered for it to execute any code. This actually does not need to be the case, which is why I didn't think it was the case. Classes that implement CatalystSerializable could be deserialized without being whitelisted, so I'll add that in a separate PR and add the option to disable the whitelisting requirement for serialized class names in another. Overriding ObjectInoutStream seems fine to still allow Serializable to be used with whitelisting. Thanks!
|
Ok, I'm not 100% sure if I was clear enough about this, so just to be sure: The serialized stream of an AppendRequest for example would look like the following: [207][term/leader/logIndex/logTerm/commitIndex][TYPE_SERIALIZABLE][Java-serialized Entry 1][TYPE_SERIALIZABLE][Java-serialized Entry 2][...] (207 is the SerializeWith ID of AppendRequest). I think it's fine that users can enable "Serializable for all" if they are sure that noone ever will get a stream of bytes from an unknown source to be passed to Serializer#readObject. In all other cases, users need to be able to whitelist their own classes and/or the package name prefixes of classes they would like to whitelist. |
Ah, wrong example. The AppendRequest will of course contain other CatalystSerializable objects as entries. But the idea of the example still works: Assume the Entry is a CommandEntry and that itself contains a Command that is only java-serializable. The serialized stream would then look like: [207][term/leader/logIndex/logTerm/commitIndex][220][TYPE_SERIALIZABLE][Java-serialized Command] where 220 is the SerializeWih ID of CommandEntry. |
Yeah, I think I understand what the problem with Java serialization is. I'm talking about CatalystSerializable and TypeSerializer as an additional, separate but related issue. The problems with Java serialization are:
Correct? What I'm saying, is the same will be true of CatalystSerializable if it does not require TypeSerializer to be registered and does allow class names to be arbitrarily loaded (which should be the case for usability reasons), correct? Currently, TypeSerializers have to be registered for CatalystSerializable objects. That needs to be changed to allow CatalystSerializable class names to be loaded (not for security but for usability reasons) in addition to whitelisting Serializable classes. So, an attacker could simply write any class name in the byte stream, and if that class implements CatalystSerializable, it will create an instance and call readObject. Sure, this implies that a CatalystSerializable class with exploitable So, I'm talking about making two different changes:
|
Yes, Serializable allows arbitrary classes to be loaded (if ObjectInputStream is not subclassed etc) and those arbitrary classes could execute code on instantiation that was received in the serialized stream (=remote code execution). I think that CatalystSerializable or generally classes for which a TypeSerializer is available are somewhat different, though. AFAIK even when #readByClass or #writeByClass is called, the object will always be de-/serialized by either a TypeSerializer or by java serialization, so we have only those two cases when thinking about de-/serialization (= from a security point of view we do not care what readByClass actually read, as that might not match the serialized data anyway, it's just used for choosing the Serializer). A user of catalyst/copycat might of course implement additional classes that implement CatalystSerializable or add new TypeSerializers and of course these may then again expose a remote code execution vulnerability - but if that engineer implements a class that way, he might also whitelist a Serializable class that would expose that vulnerability. This is then in his own responsibility. So, from my point of view, it should be enough to fix the Serializable (and Externalizable, too) vulnerability by subclassing ObjectInputStream as described above. All other code does not need any adjustment. |
You're right that a user can implement Thanks for all the input. I'm working on a solution for this now and will follow your |
Deserialization of data from untrusted users can represent a security flaw. While Copycat and Atomix clusters should never be exposed to untrusted users, there's nevertheless no good reason to have dynamic class loading and Java serialization enabled. Performance is slow for Java serialization, and dynamic class loading requires serializing class names. These features should be disabled by default in order to encourage more efficient and secure white listing of classes with space-compact serialization IDs.
The text was updated successfully, but these errors were encountered: