CVE-2012-1723 – Oracle Java Applet Field Bytecode Verifier Cache Remote Code Execution [CVE-2012-1723 OpenJDK: insufficient field accessibility checks (HotSpot, 7152811)]

by Michael 'mihi' Schierl, @mihi42

(Since I've been asked a few times how to pronounce my last name (I don't care about how you pronounce my first name, every country does it differently, and all of them are fine): Just take the English word "sheer" and add an L to it. In case you are from a country that does not differentiate between the L and the R sound, I guess you are out of luck anyway :P)

References

Note: I did not discover this vulnerability, therefore I do not claim credit for it. I only wrote up a quick POC exploit on 2012-06-13 in about an hour, so I don't think the vulnerability is hard to exploit, especially since the source patches are available (YMMV).

Credit where credit is due:

If you think your name/link is missing from that list, feel free to drop me a note via Twitter or email.

Summary

This is a vulnerability in the HotSpot bytecode verifier that has been present since at least Java 1.4. As most exploitable bytecode verifier flaws, it can be used to achieve type confusion. This article tries to explain both the vulnerability and how it can be exploited for type confusion. How to exploit type confusion to achieve code generation is outside its scope — however, after the last type confusion flaw, even criminals know their ways for doing so. If you don't (yes I hope you aren't a criminal, I meant if you don't know how to exploit it) just read my article about it (same link as above).

Bytecode and (deferred) verifying

When a class is loaded, the bytecode verifier verifies the bytecode of all its methods. However, some aspects of the bytecode (like validation of references to methods or fields) are deferred until the bytecode is executed first (or the method gets JIT-compiled). This may increase the performance of verifying classes, since some methods may not be called at all and they may refer to methods or fields of other classes which have to be loaded and verified before these references can be verified. (In addition, it might even be impossible to verify two classes who refer to each other if these steps were not deferred).

Vulnerable version of the HotSpot compiler will perform an invalid optimization when verifying deferred GETSTATIC/PUTSTATIC/GETFIELD/PUTFIELD instructions (hereafter referred to as "field access instructions") in preparation of JIT-compiling a method: If there are two field access instructions referring to the same field in the same method (or even in different methods that are compiled after each other), the referenced field is only verified once and the information is cached (technically, the field instance caches in which class it was successfully verified last, in a variable called _known_to_link_with). However, verifying of the four field access instructions is not the same: Both PUT instructions additionally verify that the field is not final (if it is in a different class than the method invoking it), and the STATIC respectively FIELD instructions verify that their target field is indeed a static respectively an instance field. As the verifying information of the first instruction is cached, it is possible to invoke the second instruction in situations where the second instruction alone could not have been verified.

Exploitation

To exploit this vulnerability, you need to craft a method with at least two different field access instructions referring to the same field, and have to force the method to be JITed while their verification is still deferred (i. e. you have to call the method a lot of times but make sure none of these executions touch those instructions, for example by passing a parameter that makes sure the method will end early in those executions). Then call it again for the effect.

Depending on which two instructions you chose, the effect is different:

In case of GETFIELD+PUTFIELD or GETSTATIC+PUTSTATIC, you can write to a public final field. This may lead to information disclosure (like overwriting System.out from a sandboxed context), or maybe worse (I did not pursue this approach further).

In case of GET/PUTFIELD and GET/PUTSTATIC, or vice versa, you can cause more interesting effects from writing to nonpublic fields over memory corruption to type confusion. Technically, that way you can read/write to a static field that has the same field offset as another public nonstatic field of the same class or vice versa. As the type verification will verify against the field mentioned in the instruction, this can be used to achieve type confusion quite easily. As the field offset of the first instance field is quite small (there are a few flags and the reference to the class object before the first field) and the field offset of a static field is always larger (there are a few dozen references to implemented interfaces, method pointers and other meta data in each class), writing to an instance field with a reference to the first static field is safe, as long as the class has enough instance fields (my POC had 100 of them). If the static field has a type of A and the instance field has a type of B, you can use this to convert an A to a B.

While my POC exploit uses a Java Applet for exploitation, the vulnerability does not depend on Swing or any other Java Applet features, therefore it can also be used to escape from the sandbox in a noninteractive environment, like JSP hosting. And since it affects all unpatched Java versions since 1.4, I believe it is the most powerful cross-platform Java vulnerability at the moment.

Conclusion

To exploit this vulnerability, you first have to craft your own bytecode (I used ObjectWeb ASM for this task, but any other tool, maybe even a hex editor, should be fine):

Then use this class follows to confuse an object from type A to B:

The resulting exploit is quite short (about 50 lines of code to craft the class, and about 50 more lines of Java code for an applet that uses this class in conjunction with the "Static ClassLoader Call" to achieve RCE), and I am sure you can make it shorter if you really try. However, I don't want to make it too easy for criminals to leverage this vulnerability just by copying and pasting; therefore I won't publish my exploit code in the near future. (Yes I'm aware that someone else will most likely build a Metasploit module from it, but then it was not my code that got ripped by the criminials...)