❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdaycode white | Blog

Blog moved to https://code-white.com/blog

5 July 2023 at 08:09

Hey,

we've moved our tech blog to our own homepage at https://code-white.com/blog. From now on, all fresh posts will go up there. We've also copied over all the old articles, so you won't miss anything. And don't worry, the existing Blogspot posts will remain intact to keep the existing links working. But from now on, make sure to check out https://code-white.com/blog and, if you're interested, our all new public vulnerabilities list.

See you there,
The CODE WHITE Team

Return of the Rhino: An old gadget revisited

4 May 2016 at 19:06
[Update 08/05/2015: Added reference to CVE-2012-3213 of James Forshaw. Thanks for the heads up]

As already mentioned in our Infiltrate '16 and RuhrSec '16 talks, Code White spent some research time to look for serialization gadgets. Apart from the Javassist/Weld gadget we also found an old but interesting gadget, only using classes from the Java Runtime Environment (so called JRE gadget).

We called the gadget Return of the RhinoΒ since the relevant gadget classes are part of the Javascript engine Rhino, bundled with Oracle JRE6 and JRE7.
As you may already know, the Rhino Script engine has already been abused in JVM sandbox escapes in the past (e.g.Β CVE-2011-3544 of Michael Schierl andΒ CVE-2012-3213 of James Forshaw).

We stumbled over the gadget just by accident as we realized that there is a huge difference between the official Oracle JRE and the JRE's bundled in common Linux distros.
Most may not know that the Rhino Script Engine is actively developed by the Mozilla Project and distributed as a standalone package/jar (packages under org.mozilla.*). Furthermore, Oracle JRE6/7 is bundling an old fork of Rhino (packages under sun.org.mozilla.*). Β Surprisingly, Oracle applied some hardening to Rhino core classes with JRE7u1513, not being serializable anymore. The changes were made to fix a sandbox escape (CVE-2012-3213) of James Forshaw (seeΒ James' blog post).

Β But those hardening changes were not incorporated into Mozilla's Rhino mainline, which happens once in a while. So the gadget still works if you are using OpenJdk bundled with Ubuntu or Debian.
Let's take a look at the static view of some Rhino core classes:



In the Rhino Javascript domain almost every Javascript language object is represented as aΒ ScriptableObjectΒ in the Java domain.
Functions, Types, Regexes and several other Javascript objects are implemented in Java classes, extending ScriptableObject.
AΒ ScriptableObjectΒ has two interesting members. A reference to its prototype object and an array of Slot objects. The slots store the properties of a Javascript object. The Slot can either be Slot, GetterSlot or RelinkedSlot. For our gadget we only focus on the GetterSlot inner class.
Every Slot class has a getValue() method used to retrieve the value of the property. In case of a GetterSlot the value is taken from a call to either a MemberBox or Function instance. And both MemberBox and Function instances do dynamic method calls using Java's Reflection API. That's already the essence of the story :-). But let's go into details.

The class NativeError is a successor of IdScriptableObject which inherits from ScriptableObject. ScriptableObject implements the tagging interface Serializable, hence allΒ successors like NativeError are serializable. The class NativeError has an interesting way of how toString() is performed:

In the very beginning toString() just calls js_toSting(this).

And now we reach the point where it gets interesting. In the first line of js_toString(), a property called "name" is retrieved from the NativeError instance using the static method ScriptableObject.getProperty().






In ScriptableObject.getProperty() the property value is retrieved by calling the IdScriptableObject.get() method which delegates the property resolution call to its ancestor ScriptableObject.

ScriptableObject gets the value of the property from the Slot instance of the Slot[] by calling the getValue() method.
In case of a ScriptableObject$GetterSlot (inner class of ScriptableObject) we finally reach the code where reflection calls are eventually happening.
As already shown in the static class view,Β ScriptableObject$GetterSlot has a member "getter" of class Object. In the getValue() method of ScriptableObject$GetterSlot two cases are checked.


In case of getter being an instance of MemberBox, the invoke method on the MemberBox instance is called which just wraps a dynamic call using Java's Reflection API.



The Method object used in the reflection call comes from the member variable "memberObject" of class MemberBox. Although "memberObject" is of type java.lang.reflect.Member, only java.lang.reflect.Method or java.lang.reflect.Constructor instances are valid classes for "memberObject". Both java.lang.reflect.Method and java.lang.reflect.Constructor are not serializable, so obviously the value of "memberObject" needs to be set in the readObject() method of MemberBox during deserialization.





Specifically, "memberObject" is set in method readMember(), creating a java.lang.reflect.Method object using values coming from the serialized object stream.








So we can control the java.lang.reflect.Method object used in the reflection call. How about the instance ("getterThis") on which method gets invoked? Is this instance also created from the serialized object stream and hence under our control? If we look back into the implementation of method ScriptableObject$GetterSlot.getValue(), we see that the value of "getterThis" depends on the value of member "delegateTo" of the MemberBox instance. "delegateTo" is marked transient and is not set in readObject() during deserialization. So the first case of the if-statement applies and "getterThis" is assigned to "start" which is our NativeError instance. And the arguments of the reflection call are just set to an empty Object[]. Bad for us, but there's hope as we will see later.

Looking again at ScriptableObject$GetterSlot.getValue() we see a second case, if "getter" is an instance of Function. The interface Function sounds very interesting.







And we have plenty of classes implementing Function, most of them being serializable.





















From all those classes the serializable NativeJavaMethod class nearly jumped into our face. Before we go into details, let's take another look at the static view of some Rhino core classes, taking the NativeJavaMethod into account.



And a quick look into the call() method revealed the following: In the beginning, the "index" variable is returned from the call to method findCachedFunction(). This method eventually calls findFunction() which calculates one MemberBox instance from the member "methods"(of type MemberBox[]) using a more or less complex algorithm. If the methods array has only one element, findCachedFunction() will just return 0 as the index value.

The variable "meth" is assigned to methods[0]. Just keep in mind that the member "methods" is under our control as it comes from the serialized object stream. At the very end of the figure we have a dynamic method invocation, as the method invoke() is called on the MethodBox instance "meth". So we can control the Method object/method to be invoked which is half the battle.



How about the target instance "javaObject". Can we control it?
We might be able to control it if "o" is an instance of Wrapper. Then, the unwrap() method on "o" is called and the return value assigned to "javaObject". "o" is assigned to "thisObject" which is our NativeError instance. NativeError is not of type Wrapper, but we can see a "for" loop which reassigns "o" to the prototype object of "o" using the getPrototype() method.
So if you can set the prototypeObject member of our NativeError instance to a Wrapper instance and get the unwrap() method to return an object under our control we are ready to go!
And the serializable class NativeJavaObject does what is needed here. It just returns the value of the member "javaObject" in its unwrap() method.


Another update to the static view of some Rhino core classes, taking NativeJavaObject into account.








So apperently the only thing we need to do is to create a NativeError instance, set its prototype to a NativeJavaObject which wraps our target instance, create a NativeJavaMethod and specify the method to be invoked on the target instance, serialize it and deserialize it again. But now we get the following exception:



Looks like we need a Context being associated with the current thread :-(
But hey! There is a static method Context.enter() which sets the Context we really need. We just need to trigger it in advance. But how to call Context.enter() if we can't use a MethodBox nor a NativeJavaMethod. To get around this, we use a trick we had known for a while:

When you do a reflection call, the target object is ignored, if the method to be invoked is a static method. That's it.



And if you look back, we already had found a call to invoke() on a MemberBox instance being triggered from method ScriptableObject$GetterSlot.getValue(). But the first argument was always our NativeError instance. As already mentioned, the first argument gets ignored if you use a static method such as Context.enter() as your target method :-).
So if we would have two property accesses on NativeError, we could then trigger a reflection call on Context.enter() using a MemberBox and then another reflection call using a NativeJavaMethod.
Luckily, we have two property accesses in method Β js_toString() of class NativeError:





The only remaining problem is how to trigger a toString() call on a NativeError object during deserialization. As you may have already seen in our Infiltrate '16 or RuhrSec '16 slidedecks you can use the "trampoline" class javax.management.BadAttributeValueExpException for that.




Getting code execution is trivial now. You can use Adam Gowdiak's technique and create a serializable com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl instance and invoke the newTransformer() method on it by using the reflection primitive of NativeJavaMethod. Or you just invoke the execute() method on a serializable com.sun.rowset.JdbcRowSetImpl instance and load a RMI class from your server (for further details see our Infiltrate '16 or RuhrSec '16 Β slidedecks).

Infiltrate 2016 Slidedeck: Java Deserialization Vulnerabilities

12 April 2016 at 14:11
The outcome of Code White's research efforts into Java deserialization vulnerabilities was presented at Infiltrate 2016 by Matthias Kaiser.

The talk gave an introduction into finding and exploiting Java deserialization vulnerabilities. Technical details about the Oracle Weblogic deserialization RCE (CVE-2015-4852) and a SAP Netweaver AS Java 0day were shown.

The slidedeck doesn't include the SAP Netweaver AS Java 0day POC and it won't be published until fixed.

It Β can be found here:
http://www.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class

Stay tuned!

CVE-2015-3269: Apache Flex BlazeDS XXE Vulnerabilty

24 August 2015 at 11:23

In a recent Product Security Review, Code White Researchers discovered a XXE vulnerability in Apache Flex BlazeDS/Adobe (see ASF Advisory). The vulnerable code can be found in the BlazeDS Remoting/AMF protocol implementation.

All versions before 4.7.1 are vulnerable. Software products providing BlazeDS Remoting destinations might be also affected by the vulnerability (e.g. Adobe LiveCycle Data Services, see APSB15-20).

Vulnerability Details

An AMF message has a header and a body. To parse the body, the method readBody() of AmfMessageDeserializer is called. In this method, the targetURI, responseURI and the length of the body are read. Afterwards, the method readObject() is called which eventually calls the method readObject() of an ActionMessageInput instance (either Amf0Input or Amf3Input).

In case of an Amf0Input instance, the type of the object is read from the next byte. If type has the value 15, the following bytes of the body are parsed in method readXml() as a UTF string.

The xml string gets passed to method stringToDocument of class XMLUtil where the Document is created using the DocumentBuilder.

When a DocumentBuilder is created through the DocumentBuilderFactory, external entities are allowed by default. The developer needs to configure the parser to prevent XXE.

Exploitation

Exploitation is easy, just send the XXE vector of your choice.

❌
❌