Unrestricted deserializing from a privileged context allows an attacker to supply crafted input which, upon deserialization, can yield objects that the attacker lacks permissions to construct. One example of this is the construction of a sensitive object, such as a custom class loader. Consequently, avoid deserializing from a privileged context. When deserializing requires privileges, programs must strip all permissions other than the minimum set required for the intended usage. See guidelines SEC12-J. Do not grant untrusted code access to classes in inaccessible packages and SEC13-J. Do not allow unauthorized construction of classes in inaccessible packages for additional information.
Noncompliant Code Example
...
(CVE-2008-5353: Zoneinfo
)
Wiki Markup |
---|
\[[CVE|AA. Bibliography#CVE]\] [CVE-2008-5353 |http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5353] describes a Java vulnerability, discovered in August 2008 by Sami Koivu. Julien Tinnes subsequently wrote an exploit that allowed arbitrary code execution on multiple platforms that ran vulnerable versions of Java. The problem resulted from deserializing untrusted input from within a privileged context. The vulnerability involves the ({{ |
ZoneInfo
object (sun.util.Calendar.Zoneinfo}}) object, which being a serializable class, is |
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
because all classes within the "sun
" package are treated as untrusted. As a result, 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 because there is no guaranteed 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
if the actual deserialized class is not a ZoneInfo
. 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, or the subclass . Also a subclass automaticall becomes serializable automatically if it derives from a serializable class. During deserialization of the subclass, the JVM calls the no-argument constructor of the most derived superclass that does not implement java.io.Serializable
either directly or indirectly. This allows it to fix the state of this most derived superclass that does not implement Serializable
. In the following code snippet that immediately follows, class A
's no-argument constructor is called when C
is deserialized because A
does not implement Serializable
. Subsequently, Object
's constructor is invoked. This procedure cannot be carried out programmatically, consequently the JVM generates the equivalent bytecode at runtime. Typically, when the superclass's constructor is called by a subclass, the subclass remains on the stack. However, in deserialization this does not happen. Only the unvalidated bytecode is present. This allows any security checks within the superclass's constructor to be bypassed , in that , the complete execution chain is not brought into scrutiny.
...
Code Block | ||
---|---|---|
| ||
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 (CVE-2008-5353: Zoneinfo
)
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
. Consequently, the code was granted the minimal set of permissions required 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. Refer to guideline SEC12-J. Do not grant untrusted code access to classes in inaccessible packages for more details on allowing or disallowing access to packages. Finally, the two-argument form of doPrivileged()
allows stripping all permissions other than the ones specified in the ProtectionDomain
.
Code Block | ||
---|---|---|
| ||
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; } |
The two-argument form of doPrivileged()
allows stripping all permissions other than the ones specified in the ProtectionDomain
. Refer to guideline SEC00-J. Avoid granting excess privileges for more details on using the two-argument doPrivileged()
method.
Risk Assessment
Deserializing objects from an unrestricted privileged context can result in arbitrary code execution.
...
Wiki Markup |
---|
\[[API 2006|AA. Bibliography#API 06]\] TODO\[[CVE|AA. Bibliography#CVE]\] [CVE-2008-5353 |http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5353] |
...
SER08-J. Do not use the default serialized form for implementation-defined invariants 16. Serialization (SER) VOID SER10-J. Do not serialize direct handles to system resources