Java used to be a favored vulnerability target for cybercriminals. However, in recent years that has not been the case. The now-fixed Java zero-day that was used in the Pawn Storm campaign was, in fact, the first time in nearly two years that a zero-day had been found and reported in Java.
This can be attributed, in part, to stepped up security measures for Java. As Oracle notes on the Java home page itself, out of date Java plugins are now disabled by major browsers. In addition, Java 7 Update 51 (released in January 2014) tightened the rules on what kind of applets could be run. By default, self-signed and unsigned applets (the ones most likely to be used by attackers) would not run by default in browsers. JRE also has click-to-play protection for all applet (signed and unsigned). Taken together, these have made Java a far less attractive platform for attackers.
Now that the Java zero-day (designated as CVE-2015-2590) has been patched, we can talk about some more technical details. This exploit has two components: one bypasses the click-to-play protection in Java. We will not disclose this portion of the vulnerability, but we can discuss the other component. As we noted earlier, this has now been fixed in the newest Java version (Java 8 Update 51).
Java provides a class ObjectInputStream to deserialize buffers to objects. The buffer (which is to be deserialized) contains the object’s class information and filed data. More details about this class can be found in the Official Java documentation.
The vulnerability is in how these objects are deserialized. An attacker can use this vulnerability to modify a field in the deserialized object (even if it is private) and introduce other class information. The Java Runtime Environment allows an attacker (in some cases) to read an object’s fields from a stream buffer even if the object or the object’s outer object’s class type is not found in the serialized buffer. The figure below shows the impact of the vulnerability:
Figure 1. Vulnerability impact
In Figure 1, the objects in the serialized objects buffer will be desterilized. During the process, Object A can intercept the desterilized process with an overriding function (for example, readResolve). In the function, the attacker coder can return to other object with other class which are not in the serialized object buffer (see the red word in F.1) to overwrite the original private field. In most cases, JRE can find it and raise exception. But if the objects, which are the outer objects of A, are crafted and overload readObject function to raise “Class Not Found ” exception. The vulnerability will trigger. In one words, the vulnerability give attacker a way to change directly one deserialized object ‘s private filed with class type which is not in the stream buffer.
How does an attack proceed?
First, an attacker crafts a serialized buffer. This contains an AtomicReferenceArray object. After exploiting the vulnerability, an AtomicReferenceArray class object’s private field array points to a Help type object array. After this step, memory layout like this:
Figure 2. Memory layout
In the above figure, the rar variable is a reference to the AtomicReferenceArray object which is deserialized and the AtomicReferenceArray object’s array references the array variable. Help is a subclass of the ClassLoader class. In other words the array variable control the AtomicReferenceArray object’s private field array.
Next, the attacker gets a current ClassLoader object.
The rar variable’s element is set to the acquired ClassLoader Object. (The attacker uses an index of 0.) Because rar.array is a reference to the Helper array, the real object of array is changed.
The type of array in this case is Help. In the Help class, an attacker can use array to access the function ClassLoader.defineClass. (This is a protected function; if an attacker directly uses the ClassLoader object to call defineClass in the current class scope, it will raise a compile error.)
An attacker can use this access to define a privileged class and close SecurityManager. This allows the attacker to run their malicious code. One can ask why the attacker didn’t use the AtomicReferenceArray public API to get the field array’s content? This is because the JRE will check whether the type’s element is correct for the type that it is to be cast to.
Overall, the steps necessary to perform this exploit are similar to other previous exploits. For example, CVE-2012-0507 used a similar technique many years ago.
Because of the severity of this vulnerability, we highly recommend that Java users update to the latest version.
Other posts related to Operation Pawn Storm can be found here:
- Pawn Storm C&C Redirects to Trend Micro IP Address
- An In-Depth Look at How Pawn Storm’s Java Zero-Day Was Used
- Pawn Storm Update: Trend Micro Discovers New Java Zero-Day Exploit
- Pawn Storm Espionage Attacks Use Decoys, Deliver SEDNIT
- Operation Pawn Storm: Putting Outlook Web Access Users at Risk
- Pawn Storm Update: iOS Espionage App Found
- Operation Pawn Storm Ramps Up its Activities; Targets NATO, White House
- Pawn Storm: First Java Zero-Day Attack in Two Years Targets NATO & US Defense Organizations