You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Unrestricted deserializing from a privileged context allows an attacker to supply crafted input which upon deserialization, can yield objects that the attacker does not have permissions to construct. Construction of a custom class loader is an example (See SEC10-J. Do not allow the unauthorized construction of sensitive classes).

Noncompliant Code Example

In Aug 2008 a vulnerability in the JDK was discovered by Sami Koivu. Julien Tinnes wrote an exploit that allowed arbitrary code execution on multiple platforms that ran vulnerable versions of Java. The problem arose primarily due to deserializing untrusted input from within a privileged context. The vulnerability involves the ZoneInfo object (sun.util.Calendar.Zoneinfo), which being a serializable class, is by design deserialized by the readObject() method of the ObjectInputStream class.

Consider the default security model of an applet that does not allow access to sun.util.calendar.ZoneInfo since all classes within the "sun" package are treated as untrusted. Thus, prior to JDK 1.6 u11, the acceptable method for an unsigned applet to deserialize a Zoneinfo object was to execute the call from a privileged context, such as a doPrivileged() block. This constitutes a vulnerability since there is no surefire method of knowing whether the serialized stream contains a Zoneinfo object and not a malicious serializable class. The vulnerable code casts the malicious object to the ZoneInfo type which typically causes a ClassCastException. This exception however, is of little consequence as it is possible to store a reference to the newly created object in some static context so that the garbage collector does not act upon it.

A non-serializable class can be extended and its subclass can be made serializable. During deserialization of the subclass, the JVM calls the non-serializable superclass's constructor (all the way upto Object's constructor) and proceeds to deserialize the necessary fields of the subclass. At this point, there is no subclass code on the stack and the superclass's constructor is executed with no restrictions since doPrivileged() takes the intersection of the privileges of all the caller codes present on the stack. Since java.util.Calendar is trusted, it exhibits full system privileges when used with a doPrivileged() block.

For exploiting this condition, often, a custom class loader is desirable. Instantiating a class loader object requires special permissions that are made available by the security policy that is enforced by the SecurityManager. An unsigned applet cannot carry out this step by default. If an unsigned applet can execute a custom class loader's constructor, it can effectively bypass all the security checks (since it has the requisite privileges as a direct consequence of the vulnerability). A custom class loader can be designed to extend the System Class Loader, undermine security and carry out forbidden functions such as reading or deleting files on the user’s filesystem. Moreover, any legitimate security checks in the constructor are meaningless as the code is granted all privileges.

try {
  ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged(
    new PrivilegedExceptionAction() {
      public Object run() throws Exception {
        return input.readObject();
      }
  });
  if (zi != null) {
    zone = zi;
  }
 } catch (Exception e) {
 }

Compliant Solution

This vulnerability was fixed in JDK v1.6 u11 by defining a new AccessControlContext INSTANCE, with a new ProtectionDomain. The ProtectionDomain encapsulated a RuntimePermission called accessClassInPackage.sun.util.calendar. Therefore, the code was granted just about enough permissions to access the sun.util.calendar class. This whitelisting approach guaranteed that a security exception would be thrown in all other cases of invalid access.

private static class CalendarAccessControlContext {
  private static final AccessControlContext INSTANCE;
    static {
      RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
      PermissionCollection perms = perm.newPermissionCollection();
      perms.add(perm);
      INSTANCE = new AccessControlContext(new ProtectionDomain[] {
        new ProtectionDomain(null, perms)
      });
    }
  }

// ...
try {
zi = AccessController.doPrivileged(
       new PrivilegedExceptionAction<ZoneInfo>() {
         public ZoneInfo run() throws Exception {
           return (ZoneInfo) input.readObject();
         }
       }, CalendarAccessControlContext.INSTANCE);
} catch (PrivilegedActionException pae) { /* ... */ }
} catch (Exception e) { }
if (zi != null) {
  zone = zi;
}

Risk Assessment

Deserializing objects from a privileged context can lead to arbitrary code execution.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SER37-J

high

unlikely

medium

P6

L2

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

[[API 06]]
TODO


SER36-J. Do not use the default serialized form for implementation defined invariants      11. Serialization (SER)      11. Serialization (SER)

  • No labels