The driver afd.sys is responsible for handling socket connections.  MS08-066 addresses several vulnerabilities in afd.sys that could allow an attacker to execute arbitrary code in kernel mode. These vulnerabilities can only be exploited locally and there is no remote vector from our investigations.

One of these vulnerabilities involves a ProbeForRead / ProbeForWrite bypass when using user supplied memory pointers and lengths.  We have blogged before about ways to bypass these functions and how to protect your drivers from these vulnerabilities.  In that post, we talked about an attacker bypassing checks by using a zero length.  The update today is a new type of bypass in that the driver does not validate the entire range passed in.

Let's look at some piece of source code:

// Attacker controls OutputBuffer and OutputBufferLength
void IOCTL_handler(...) {
[...]
        try {
            ProbeForWrite (OutputBuffer,
                                OutputBufferLength, //  [1] length could be zero and this will be bypassed even with a kernel mode address
                                sizeof (UCHAR));

            RtlCopyMemory(
                OutputBuffer,
                (PUCHAR)context+endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
                endpoint->Common.VcConnecting.RemoteSocketAddressLength  // [2] copy based on a non-zero value to a kernel mode address
                );

        } except( AFD_EXCEPTION_FILTER(&status) ) {
        
        }
[...]
}

The vulnerability in the above could happen when the driver validates a range of memory to be inside user mode address space but later uses a different range for copying. In this case, an attacker can supply the range (addr=kernelmode, size=0) bypassing the ProbeForWrite check as we can see at [1], but the driver will later use (addr=kernelmode,endpoint->Common.VcConnecting.RemoteSocketAddressLength) writing to a kernel mode address as we can see at [2].

A security minded kernel developer could fix this in such a way validating OutputBufferLength and using it twice.

void IOCTL_handler(...) {
[...]
         if (OutPutBufferLength!=endpoint->Common.VcConnecting.RemoteSocketAddressLength) {
             //bail out... 
             return;
         }
         try {           

            ProbeForWrite (OutputBuffer,
                                OutputBufferLength, 
                                sizeof (UCHAR));
            RtlCopyMemory(
                OutputBuffer,
                (PUCHAR)context+endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
                OutPutBufferLength  
                );

         } except( AFD_EXCEPTION_FILTER(&status) ) {
        
         }
[...]
}

Part of our MSRC process is to look for variations in the area of each reported vulnerability and give feedback to the engineering groups so our future code does not contain these issues.  In this case, we applied three parallel strategies:

1 – Fuzzed the IOCTL handlers
2 – Applied binary static analysis tools on top of phoenix
3 – Source code review of the area

We hope this blog post helps you understand MS08-066 and gives you an idea of what to look out for in your code.

- Fermin J. Serna, SVRD Blogger

*Postings are provided "AS IS" with no warranties, and confers no rights.*