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.

Sunday, 6 June 2010

The Quest : Part 2

So the last try at making a small Mach-O binary didn't really work. Now I could start fiddling with the linker to see if I can make things smaller but I am not particularly up on my Apple linker usage so instead lets just straight to the binary assembler :)

Fortunately Apple choose to install nasm by default (well when you install the developers' tools), so we just need to understand how a mach-o binary is laid out. This is some official documentation about the file format (and there is the referenced header files installed with the dev tools). Using the otool utility also gives a good idea of what is in a real binary (try running with the -l command on the previous static binary to see what you get).

Anyway as with last time I still want this executable to not require any dirty tricks, although looking at the file format there isn't many obvious ones we could employ (at least compared to some of the stunts you can play with ELFs).

So what needs to be in a valid mach-o? The header, obviously, is required, then a number of load commands. It turns out (through a bit of reading the source) that you only actually need a LC_UNIXTHREAD (or LC_THREAD) command and the executable will load, seems unlike most other executable formats the entry point is not a field in the headers but is inferred by specifying the initial thread context.

Of course without any code in memory this isn't exactly that useful (well not immediately) so we also need to specify an LC_SEGMENT load command. This will map some of our binary into memory and we are ready to go. As a short aside if you look at the output of otool -l under most segments there are also sections, these are as far as I can tell unnecessary, and are more meta-data to make linking more consistent.
; A basic Mach-O executable
; (c) Tyranid 2010
BITS 32

ORG 0x1000

_program_start:

; mach_header
dd 0xfeedface ; MH_MAGIC
dd 7 ; cputype
dd 3 ; cpusubtype
dd 2 ; filetype
dd 2 ; ncmds
dd _cmd_end-_cmd_start ; sizeofcmds
dd 0x2001 ; flags

_cmd_start:

_segment_cmd:
dd 1 ; LC_SEGMENT
dd _segment_cmd_end-_segment_cmd ; sizeofcmd
_segment_name: ; segname
db "__TEXT"
times 16-$+_segment_name db 0
dd _program_start ; vmaddr
dd ((_program_end-_program_start)+4095)&~4095 ; vmsize
dd 0 ; fileofs
dd _program_end-_program_start ; filesize
dd 7 ; maxprot
dd 5 ; initprot
dd 0 ; nsects
dd 4 ; flags

_segment_cmd_end:

_thread_cmd_start:
dd 5 ; LC_UNIXTHREAD
dd _thread_cmd_end-_thread_cmd_start ; sizeofcmd
dd 1 ; flavor (i386_THREAD_STATE)
dd (_registers_end-_registers_start)/4 ; count

_registers_start:
dd 0 ; unsigned int __eax;
dd 0 ; unsigned int __ebx;
dd 0 ; unsigned int __ecx;
dd 0 ; unsigned int __edx;
dd 0 ; unsigned int __edi;
dd 0 ; unsigned int __esi;
dd 0 ; unsigned int __ebp;
dd 0 ; unsigned int __esp;
dd 0x1F ; unsigned int __ss;
dd 0 ; unsigned int __eflags;
dd _start ; unsigned int __eip;
dd 0x17 ; unsigned int __cs;
dd 0x1F ; unsigned int __ds;
dd 0x1F ; unsigned int __es;
dd 0 ; unsigned int __fs;
dd 0 ; unsigned int __gs;
_registers_end:

_thread_cmd_end:

_cmd_end:

_start:
; Call exit(42)
push byte 42
push byte 1
pop eax
push eax
int 0x80

_program_end:

Throw it through nasm in binary mode and what do we get? 172 bytes, far smaller. There are some further tricks you could play with this, such as embedding the code inside the thread context (as only EIP and probably the segment registers are important) or actually store a few of the necessary values in the context to slightly reduce the pushes. Still 172 is alright for now, can it go any lower?

Thursday, 3 June 2010

The Quest for a Small Mach-O

For my sins I have recently actually enjoyed using OS X. There is just something about its unix'ness which appeals to me (though I would rather not have to pay for it to begin with). Anyway one of the first things I tend to do on an OS is to try and write as small an executable as possible and this is not the time to change that.

So this is maybe the first post of many on creating something small :) Note: I am working on Snow Leopard and producing 32bit code, YMMV.

Step 1: What can we do with basic tools?

So lets start with a normal development environment to see what we can get without having to writing anything custom. Before we can do anything we need some code, here is a simple entry point with no reliance on external libraries, just straight into the exit syscall.
void start(void) {
// Call exit(0)
__asm__ volatile (
"push $0\n"
"movl $1, %eax\n"
"int $0x80\n"
);
}
It is worth pointing out that without this exit syscall your new application will just SIGBUS, not exactly optimal.

Now just need to link it, we will choose to link statically (which should get rid of anything to do with the dynamic linker, which might have to change as we go along).
all: test1

test1: test1.c
$(CC) -c -o test1.o test1.c
$(LD) -o test1 -s -static -e _start test1.o

clean:
rm -f test1 *.o
And our survey says? 4096 bytes, bugger. Well I guess page alignment is a killer. Of course using hexdump shows that over 3/4 of the file is empty. Still there is some hope for the future, running otool -lv over the output application shows that the entire 4k is being loaded into memory, a classic trick in making small binaries. Some nice sounding options in the ld man page (such as -pagezero_size and -seg_page_size) just don't seem to work as expected so no doubt something more custom is required next time.

Onwards and upwards.