Showing posts with label Serialization. Show all posts
Showing posts with label Serialization. Show all posts

Monday, 24 November 2014

Stupid is as Stupid Does When It Comes to .NET Remoting

Finding vulnerabilities in .NET is something I quite enjoy, it generally meets my criteria of only looking for logic bugs. Probably the first research I did was into .NET serialization where I got some interesting results, and my first Blackhat USA presentation slot. One of the places where you could abuse serialization was in .NET remoting, which is a technology similar to Java RMI or CORBA to access .NET objects remotely (or on the same machine using IPC). Microsoft consider it a legacy technology and you shouldn't use it, but that won't stop people.

One day I came to the realisation that while I'd talked about how dangerous it was I'd never released any public PoC for exploiting it. So I decided to start writing a simple tool to exploit vulnerable servers, that was my first mistake. As I wanted to fully understand remoting to write the best tool possible I decided to open my copy of Reflector, that was my second mistake. I then looked at the code, sadly that was my last mistake.

TL;DR you can just grab the tool and play. If you want a few of the sordid details of CVE-2014-1806 and CVE-2014-4149 then read on.

.NET Remoting Overview

Before I can describe what the bug is I need to describe how .NET remoting works a little bit. Remoting was built into the .NET framework from the very beginning. It supports a pluggable architecture where you can replace many of the pieces, but I'm just going to concentrate on the basic implementation and what's important from the perspective of the bug. MSDN has plenty of resources which go into a bit more depth and there's always the official documentation MS-NRTP and MS-NRBF. A good description is available here.

The basics of .NET remoting is you have a server class which is derived from the MarshalByRefObject class.  This indicates to the .NET framework that this object can be called remotely. The server code can publish this server object using the remoting APIs such as RemotingConfiguration.RegisterWellKnownServiceType. On the client side a call can be made to APIs such as Activator.GetObject which will establish a transparent proxy for the Client. When the Client makes a call on this proxy the method information and parameters is packaged up into an object which implements the IMethodCallMessage interface. This object is sent to the server which processes the message, calls the real method and returns the return value (or exception) inside an object which implements the IMethodReturnMessage interface.

When a remoting session is constructed we need to create a couple of Channels, a Client Channel for the client and a Server Channel for the server. Each channel contains a number of pluggable components called sinks. A simple example is shown below:


The transport sinks are unimportant for the vulnerability. These sinks are used to actually transport the data in some form, for example as binary over TCP. The important things to concentrate on from the perspective of the vulnerabilities are the Formatter Sinks and the StackBuilder Sink.

Formatter Sinks take the IMethodCallMessage or IMethodReturnMessage objects and format their contents so that I can be sent across the transport. It's also responsible for unpacking the result at the other side. As the operations are asymmetric from the channel perspective there are two different formatter sinks, IClientChannelSink and IServerChannelSink.

While you can select your own formatter sink the framework will almost always give you a formatter based on the BinaryFormatter object which as we know can be pretty dangerous due to the potential for deserialization bugs. The client sink is implemented in BinaryClientFormatterSink and the server sink is BinaryServerFormatterSink.

The StackBuilder sink is an internal only class implemented by the framework for the server. It's job is to unpack the IMethodCallMessage information, find the destination server object to call, verify the security of the call, calling the server and finally packaging up the return value into the IMethodReturnMessage object.

This is a very high level overview, but we'll see how this all interacts soon.

The Exploit

Okay so on to the actual vulnerability itself, let's take a look at how the BinaryServerFormatterSink processes the initial .NET remoting request from the client in the ProcessMessage method:

IMessage requestMsg;

if (this.TypeFilterLevel != TypeFilterLevel.Full)
{
     set = new PermissionSet(PermissionState.None);
     set.SetPermission(
           new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
}
try
{
    if (set != null)
    {
        set.PermitOnly();
    }
    requestMsg = CoreChannel.DeserializeBinaryRequestMessage(uRI, requestStream, 
               _strictBinding, TypeFilterLevel);
}
finally
{
    if (set != null)
    {
         CodeAccessPermission.RevertPermitOnly();
    }
}
We can see in this code that the request data from the transport is thrown into the DeserializeBinaryRequestMessage. The code around it is related to the serialization type filter level which I'll describe later. So what's the method doing?
internal static IMessage DeserializeBinaryRequestMessage(string objectUri, 
              Stream inputStream, bool bStrictBinding, TypeFilterLevel securityLevel)
{
    BinaryFormatter formatter = CreateBinaryFormatter(false, bStrictBinding);
    formatter.FilterLevel = securityLevel;
    UriHeaderHandler handler = new UriHeaderHandler(objectUri);
    return (IMessage) formatter.UnsafeDeserialize(inputStream, 
              new HeaderHandler(handler.HeaderHandler));
}

For all intents and purposes it isn't doing a lot. It's passing the request stream to a BinaryFormatter and returning the result. The result is cast to an IMessage interface and the object is passed on for further processing. Eventually it ends up passing the message to the StackBuilder sink, which verifies the method being called is valid then executes it. Any result is passed back to the client.

So now for the bug, it turns out that nothing checked that the result of the deserialization was a local object. Could we instead insert a remote IMethodCallMessage object into the serialized stream? It turns out yes we can. Serializing an object which implements the interface but also derived from MarshalByRefObject serializes an instance of an ObjRef class which points back to the client.

But why would this be useful? Well it turns out there's a Time-of-Check Time-of-Use vulnerability if an attacker could return different results for the MethodBase property. By returning a MethodBase for Object.ToString (which is always allowed) as some points it will trick the server into dispatching the call. Now once the StackBuilder sink goes to dispatch the method we replace it with something more dangerous, say Process.Start instead. And you've just got arbitrary code to execute in the remoting service.

In order to actually exploit this you pretty much need to implement most of the remoting code manually, fortunately it is documented so that doesn't take very long. You can repurpose the existing .NET BinaryFormatter code to do most of the other work for you. I'd recommand taking a look at the github project for more information on how this all works.

So that was  CVE-2014-1806, but what about CVE-2014-4149? Well it's the same bug, MS didn't fix the TOCTOU issue, instead they added a call to RemotingServices.IsTransparentProxy just after the deserialization. Unfortunately that isn't the only way you can get a remote object from deserialization. .NET supports quite extensive COM Interop and as luck would have it all the IMessage interfaces are COM accessible. So instead of a remoting object we instead inject a COM implementation of the IMethodCallMessage interface (which ironically can be written in .NET anyway). This works best locally as they you don't need to worry so much about COM authentication but it should work remotely. The final fix was to check if the object returned is an instance of MarshalByRefObject, as it turns out that the transparent COM object, System.__ComObject is derived from that class as well as transparent proxies.

Of course if the service is running with a TypeFilterLevel set to Full then even with these fixes the service can still be vulnerable. In this case you can deserialize anything you like in the initial remoting request to the server. Then using reflecting object tricks you can capture FileInfo or DirectoryInfo objects which give access to the filesystem at the privileges of the server. The reason you can do this is these objects are both serializable and derive from MarshalByRefObject. So you can send them to the server serialized, but when the server tries to reflect them back to the client it ends up staying in the server as a remote object.

Real-World Example

Okay let's see this in action in a real world application. I bought a computer a few years back which had pre-installed the Intel Rapid Storage Technology drivers version 11.0.0.1032 (the specific version can be downloaded here). This contains a vulnerable .NET remoting server which we can exploit locally to get local system privileges. A note before I continue, from what I can tell the latest versions of these drivers no longer uses .NET remoting for the communication between the user client and the server so I've never contacted Intel about the issue. That said there's no automatic update process so if, like me you had the original insecure version installed well you have a trivial local privilege escalation on your machine :-(

Bringing up Reflector and opening the IAStorDataMgrSvc.exe application (which is the local service) we can find the server side of the remoting code below:

public void Start()
{
    BinaryServerFormatterSinkProvider serverSinkProvider
        new BinaryServerFormatterSinkProvider {
           TypeFilterLevel = TypeFilterLevel.Full
    };
    BinaryClientFormatterSinkProvider clientSinkProvider = new BinaryClientFormatterSinkProvider();
    IdentityReferenceCollection groups = new IdentityReferenceCollection();

    IDictionary properties = new Hashtable();
    properties["portName"] = "ServerChannel";
    properties["includeVersions"] = "false";
    mChannel = new IpcChannel(properties, clientSinkProvider, serverSinkProvider);
    ChannelServices.RegisterChannel(mChannel, true);
    mServerRemotingRef = RemotingServices.Marshal(mServer,
        "Server.rem", typeof(IServer));
    mEngine.Start();
}

So there's a few thing to note about this code, it is using IpcChannel so it's going over named pipes (reasonable for a local service). It's setting the portName to ServerChannel, this is the name of the named pipe on the local system. It then registers the channel with the secure flag set to True and finally it configures an object with the known name of Server.rem which will be exposed on the channel. Also worth nothing it is setting the TypeFilterLevel to Full, we'll get back to that in a minute.

For exploitation purposes therefore we can build the service URL as ipc://ServerChannel/Server.rem. So let's try sending it a command. In this case I had updated for the fix to CVE-2014-1806 but not for CVE-2014-4149 so we need to pass the -usecom flag to use a COM return channel.


Well that was easy, direct code execution at local system privileges. But of course if we now update to the latest version it will stop working again. Fortunately though I highlighted that they were setting the TypeFilterLevel to Full. This means we can still attack it using arbitrary deserialization. So let's try and do that instead:


In this case we know the service's directory and can upload our custom remoting server to the same directory the server executes from. This allows us to get full access to the system. Of course if we don't know where the server is we can still use the -useser flag to list and modify the file system (with the privileges of the server) so it might still be possible to exploit even if we don't know where the server is running from.

Mitigating Against Attacks

I can't be 100% certain there aren't other ways of exploiting this sort of bug, at the least I can't rule out bypassing the TypeFilterLevel stuff through one trick or another. Still there are definitely a few ways of mitigating it. One is to not use remoting, MS has deprecated the technology for WCF, but it isn't getting rid of it yet.

If you have to use remoting you could use secure mode with user account checking. Also if you have complete control over the environment you could randomise the service name per-deployment which would at least prevent mass exploitation. An outbound firewall would also come in handy to block outgoing back channels. 


Tuesday, 14 October 2014

A Tale of Two .NET Methods

Sometimes the simplest things amuse me. Take for example CVE-2014-0257 which was a bug in the way DCOM was implemented in .NET which enabled an Internet Explorer sandbox escape. Via the DCOM interface you could call the System.Object.GetType method then command the reflection APIs to do anything you like, such as popping the calculator. The COM interface, _Object, which exposed the GetType method only has 4 functions on it, it seemed pretty unlucky that 25% of the interface had a security vulnerability. Still Microsoft fixed this bug and all's well with the world. Then again if you were lucky enough to see any of my IE11 sandbox presentations you might have seen the following slide, although briefly:

Why would I point out the Equals method as well? Well because it also has a bug, one so difficult to fix that basically Microsoft has throw up its hands and given up on Managed DCOM. They've mitigated the issue in the OneClick deployment service (CVE-2014-4073) by reimplementing the DCOM object in native code, but as far as I'm aware they've not fixed the underlying issue.

To understand the problem we have to go back to CVE-2014-0257 and understand why it worked. When the GetType method returns a System.Type instance over DCOM it wraps the object in a COM Callable Wrapper (CCW). This looks to the COM infrastructure as a normal pass-by-reference object so the Type instance stays in the original process (say the ClickOnce service) but exposes the remote COM interfaces to the caller. The Type class is marked as Serializable so why doesn't the CCW implement IMarshal and custom-marshal the object to the caller? It would be a pretty rude thing to do, It would force the CLR to be loaded into a process just because it happened to be communicating with a .NET DCOM server.

If you implement similar code in C# though things change. The result of calling GetType is a local instance of the Type class. How does .NET know how to do this? This is where the IManagedObject interface gets involved. Every CCW implements the IManagedObject interface which has two methods, GetObjectIdentity which is used to determine if the object exists in the same AppDomain and GetSerializedBuffer which, well, I guess the name describes itself.

When a .NET client receives a COM object it tries to see if it's really a .NET object in disguise. To do this it calls QueryInterface for IManagedObject, if that succeed it will then call GetObjectIdentity to see if it's already in the same AppDomain (if so it can just call it directly). Finally it will call GetSerializedBuffer, if the wrapped .NET object is Serializable it will receive a serialized version of the object which it can recreate using the BinaryFormatter class. Yes that BinaryFormatter class.

Oh crap!

This of course works in reverse, if a COM client passes a .NET object to a DCOM server it can cause arbitrary BinaryFormatter deserialization in the server. The Equals method will accept any object by design. So by passing a malicious serializable .NET object to Equals you can end up doing fun things like reflecting an arbitrary Delegate over the DCOM interface. As you can imagine that's bad.

At this point I'll direct you the exploit code, which should make everything clearer, or not. There's actually a lot more to the exploit than it seems :-)

Saturday, 2 February 2013

Fun with Java Serialization and Reflection

Last year I started to have a poke at Java for security vulnerabilities, I am not really sure why, but probably because I was having some success breaking .NET and felt Java was likely to have similar issues. Shame I picked a bad time to do so if I wanted to be famed for owning Java (re: Security Explorations). Still I think I found a few things Adam Gowdiak didn't find :)

Anyway, with the recent fixing of my last Java vulnerability in 7 update 13 (CVE-2012-3213 if  you care) I felt it was a good time to describe what it did and how it worked, especially as it is a mixture of the classic Java serialization vulnerabilities mixed with the hot topic of reflection, making it an interesting vulnerability. It will also describe another source of access to protected package Class objects.

The underlying issue is in the Rhino script engine. This is a Javascript interpreter built into modern versions of the JRE (from version 6 onwards) and originally comes from a Mozilla project where it was primarily designed to run in a fully trusted environment. It has had security issues before (for example see CVE-2011-3544) as Sun/Oracle decided to make it work in a sandboxed Java environment. However to exploit what I found you have to be a bit creative.

A Quick Overview of Rhino Security

As the script engine could potentially create user-defined but trusted code one of the things that was added to the engine was some checks to prevent sandboxed code from calling into objects which might have dangerous side effects, for example gaining access to protected packages such as 'sun.*'. In order to access a native Java object the engine must first wrap it with a scriptable wrapper by using a WrapFactory. The JRE provides a custom implementation in com.sun.script.javascript.RhinoWrapFactory which does these checks before the Javascript is allowed to call methods on that object. In that code it checks things like whether the object is a ClassLoader (which might allow the script to bypass package access checks in loadClass etc.), it also checks for the package name of Class objects and classes to see if they are visible to scripts (ultimately calling the current security manager's checkPackageAcccess method). There are some exclusions though, because the core Rhino classes are actually embedded within the sun.* package which means it can at least get access to those. At any rate what this ultimately results in is I couldn't see an immediate way of using the script engine to call into protected classes to do something nasty.

Bug Hunting in the Javascript World

The fact that these wrapping mechanisms are needed are a good example of some of the differences between Java and Javascript. You could consider Javascript to have one of the most flexible reflection implementations, all objects are reflectable (well of course depending on the implementation), for example to determine what properties and functions an object supports you can do something as simple as:

for(x in obj)
{
    System.println(x+": " + typeof(obj[x])");
}
You can dispatch methods or read properties by just using the obj[x] syntax. The Rhino script engine aims to  replicate this functionality even for native Java objects by providing isolated scriptable wrappers around common reflection primitives such as methods, fields and constructors. You can find these under the sun.org.mozilla.javascript.internal package with classes such as NativeJavaConstructor and NativeJavaMethod. The interesting thing I noticed was these were not performing any further reflection checks on the classes they were interacting with, presumably if you could get access to one of these classes you must have already gone through the object wrapping process and that would have blocked the package access. And so it seems, after a bit of digging I managed to find the syntax for getting access to the constructor object using the following code:

importClass(Packages.sun.swing.SwingLazyValue); 

SwingLazyValue['(java.lang.String,java.lang.String,java.lang.Object[])'];

This would get you a constructor on the SwingLazyValue class (which is a useful execution pivot in the JRE to call internal static functions, especially as it is based on a public interface we can access and call through). But if you try this in a sandboxed environment it fails with an exception due to the package access of the Class object, so close but so far. Still there is clearly a way of exploiting it otherwise I wouldn't be documenting it.

Serialization to the Rescue

If you look at the class hierarchy of the NativeConstructor class you will notice something interesting (or at least you would have done prior to update 13), it implemented the Serializable interface. So perhaps instead of using Javascript to access the constructor we could instead use serialization. The advantage of this approach is we might be able to reconstruct the object in native Java code first (which won't necessarily complain about it) and then pass it back into Javascript for the final exploitation.

I knocked up a simple full trust application which would capture a NativeConstructor object, serialize it then check it deserialized correctly. I went to run it, but it threw an exception because some internal fields could not be serialized. Damn... Looking through the documentation it looks like serialization was a vestigial feature of the original Mozilla implementation, Sun had not bothered to ensure it still worked correctly, so I followed a hunch, perhaps the object doesn't actually need those unserializable fields, perhaps I can just remove them. Fortunately Java makes it relatively easy to do this by implementing the replaceObject method on the java.io.ObjectOutputStream class.

A few minutes later I had:

class MyObjectOutputStream extends ObjectOutputStream {
   public MyObjectOutputStream(OutputStream stm) throws Throwable {
       super(stm);
       enableReplaceObject(true);
   }

   protected Object replaceObject(Object o) {
       String name = o.getClass().getName();
       if(name.startsWith("com.sun.script.javascript.")) {
          return null;
       }
       return o;
   }
}

Running this in my full trust application my hunch was proven correct, the script didn't in fact need those internal fields to work and the NativeConstructor object could be used freely when deserialized. Feeling the end was in sight I plugged it into an Applet, I took the binary output from the full trust application and deserialized it, I was dissappointed to be greeted with:

java.security.AccessControlException: access denied 
   ("java.lang.RuntimePermission" 
    "accessClassInPackage.sun.org.mozilla.javascript.internal")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java)
at sun.applet.AppletSecurity.checkPackageAccess(AppletSecurity.java)
at sun.applet.AppletClassLoader.loadClass(AppletClassLoader.java)
at java.lang.ClassLoader.loadClass(ClassLoader.java)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java)
at Demo.doExploit(Demo.java)

So I seemed to have gained nothing, I traded a package access check for one type to one from the Rhino implementation. Still all was not lost, I had a plan.

Ask and You Shall Receive

Now if you look at the stack trace of the exception one method frame is clearly responsible for it, the java.io.ObjectInputStream.resolveClass method. If you go and look at the implementation of that it is passing the current class loader into the forName method, which in an Applet is the AppletClassLoader which doesn't much care for handing out references to sun.* package classes. Still serialization in Java (compared to .NET with which I have bit of experience) is an unprivileged operation, even sandboxed code can do it, and there are also some things you can do to modify the process of serialization to do some funky things, like overriding the resolveClass implementation. So this led me to the realization that perhaps if I could get the protected Class objects from somewhere else then I could implement my own ObjectInputStream, override the resolveClass method and return what I needed. So I put together:

class MyObjectInputStream extends ObjectInputStream {
   Hashtable dict;

   public MyObjectInputStream(InputStream stm, Hashtable dict) 
          throws IOException {
      super(stm);
      this.dict = dict;
   }

   protected Class resolveClass(ObjectStreamClass clazz) 
         throws Throwable {
      
      if(dict.containsKey(clazz.getName())) {
          return (Class)dict.get(clazz.getName());
      } else {
          return super.resolveClass(clazz);
      }
   }
}

This class would take a Hashtable containing some classes, if we already had the required Class object we could return it as is so we don't get the security exception, but of course this begs the question, how will we populate the dictionary? Well the key is in serialization itself.

We already know that the the NativeJavaConstructor class is serializable, we also know untrusted code can perform the serialization process and that untrusted code can create the NativeJavaConstructor objects as long as they point to non-privileged classes. So can we not use the serialization process against itself to get access to all the classes we need?

Turns out we cannot directly use the ObjectOutputStream with the overloaded replaceObject method as that is actually one of the few privileged operations in the serialization process (something to do with access to private fields or something). Anyway so we will go to the source of how ObjectOutputStream determines what to serialize, the ObjectStreamClass class. You can call this from untrusted code and it will return you a description of the object, including the classes of the object's fields. From this you can take copies of the classes and keep them for the input stream to use. Such as:

public void captureTypes(Object o) {
   try {
       Class c = o.getClass();

       while(c != Object.class) {
            dict.putClass(c);

            ObjectStreamClass stmClass = ObjectStreamClass.lookup(c);
            ObjectStreamField[] fs = stmClass.getFields();

            for(int i = 0; i < fs.length; ++i) {
                Class fc = fs[i].getType();
                dict.putClass(fc);
            } 

            c = c.getSuperclass();
        }

  } catch(Throwable e) {}
}

This fills in the dictionary and you are good to go. And amazingly this does work... From that I could do things like create my SwingLazyValue which would call a static method such as SunToolkit.getField and that was the end of the road for the sandbox. Of course how you actually go about getting the sun.swing.SwingLazyValue Class object is left as an exercise for the reader ;)

Conclusion

Well it looks like the fix was simple in 7u13, anything within Rhino which could be serialized now cannot which considering they never were without substantial effort I guess isn't an issue from a break-compatibility point of view. But it does once again show that package access restrictions, especially with serialization are not adequate to protect Java from itself.