...
Code Block | ||
---|---|---|
| ||
public final class Lottery { // ... } |
Noncompliant Code Example (AtomicReferenceArray<>
)
CVE-2012-0507 describes an exploit that managed to bypass Java's applet security sandbox and run malicious code on a remote user's machine. The exploit deserialized a malicious object that subverted Java's type system. The malicious object was an array of two objects. The second object was an AtomicReferenceArray<>
whose internal array was the first object. However, while the first object was an array of Help
objects (which inherited from ClassLoader
, the AtomicReferenceArray<>
's internal array is an array of Object
. This meant that the malicious code could use AtomicReferenceArray.set(ClassLoader)
to create a Help
object. (Creation of class loaders is forbidden by the applet security manager.)
This exploit worked because in Java versions prior to 1.7.0_02 the AtomicReferenceArray<>
object performed no validation on its internal array.
Code Block | ||||
---|---|---|---|---|
| ||||
public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final long serialVersionUID = -6209656149925076980L;
// Rest of class...
// No readObject() method, relies on default readObject
}
|
Compliant Solution (AtomicReferenceArray<>
)
This exploit was mitigated in Java 1.7.0_03 by having the AtomicReferenceArray<>
validate its array upon deserialization. The readObject()
method inspects the array contents, and if the array is of the wrong type, it copies the array, foiling the exploit.
Code Block | ||||
---|---|---|---|---|
| ||||
public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final long serialVersionUID = -6209656149925076980L;
// Rest of class...
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Note: This must be changed if any additional fields are defined
Object a = s.readFields().get("array", null);
if (a == null || !a.getClass().isArray())
throw new java.io.InvalidObjectException("Not array type");
if (a.getClass() != Object[].class)
a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
unsafe.putObjectVolatile(this, arrayFieldOffset, a);
}
}
|
Risk Assessment
Using the default serialized form for any class with implementation-defined invariants may result in the malicious tampering of class invariants.
...
[API 2006] | Class |
Item 75, Consider using a custom serialized form | |
| |
Chapter 11, Object Serialization, Validation | |
Antipattern 8. Believing deserialisation is unrelated to construction | |
Metasploit: Java AtomicReferenceArray Type Violation Vulnerability |